-
Notifications
You must be signed in to change notification settings - Fork 920
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
Update import api to have data source id to allow import saved objects from uploading files to have data source #5777
Merged
bandinib-amzn
merged 40 commits into
opensearch-project:main
from
yujin-emma:dev-import-api
Feb 6, 2024
Merged
Changes from 39 commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
cdbefdc
update import api only
yujin-emma a237e7a
fix the local cluster 404 Not Found error and import.test integration…
yujin-emma 7bb5b3c
format import api
yujin-emma 096681b
fix resolve import error api integration test failure
yujin-emma 702e101
remove unused wait
yujin-emma b1bf360
update CHANGELOG for import api change
yujin-emma 09970b7
fix the bug when collect daved object
yujin-emma dd7dc3a
resolve comments
yujin-emma bf58206
add more test
yujin-emma d5fb6f2
fix the failed test
yujin-emma c8e771a
fix the failed test
yujin-emma cfa6266
fix the bug when import create new with data source
yujin-emma d152782
update import api only
yujin-emma 72eec26
fix the local cluster 404 Not Found error and import.test integration…
yujin-emma 57b9c82
format import api
yujin-emma fe97695
fix resolve import error api integration test failure
yujin-emma 050841e
remove unused wait
yujin-emma c32ff6f
update CHANGELOG for import api change
yujin-emma c02f9f2
fix the bug when collect daved object
yujin-emma 0d23d4b
resolve comments
yujin-emma 896b661
add more test
yujin-emma 53e8936
Update CHANGELOG.md
yujin-emma 54d2ebb
Clean up post-rebase artifacts
AMoo-Miki 8b1a3f4
refactor the generate id logic
yujin-emma 336b111
rename some test parameters
yujin-emma 8571a6f
fix the bug that create new with data source conflict
yujin-emma 7a2b14a
fix the bug that create new with data source conflict
yujin-emma b392d82
fix when first check conflict and auto override, the result are creat…
yujin-emma 9b0d78c
fix the overriden bug
yujin-emma 09996c3
Merge branch 'opensearch-project:main' into dev-import-api
yujin-emma dccbe4c
refactor code
yujin-emma 7714943
Merge branch 'dev-import-api' of github.com:yujin-emma/OpenSearch-Das…
yujin-emma ddc0aa9
fix the overriden bug by refactoring check data source conflict
yujin-emma 4826769
fix test
yujin-emma 772a582
fix test
yujin-emma 08713d4
back to mainline yaml
yujin-emma 0abb801
remove local yaml change
yujin-emma 66c1901
add test
yujin-emma 951ce61
remove unused var
yujin-emma 99b6c68
remove unused console log
yujin-emma File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
150 changes: 150 additions & 0 deletions
150
src/core/server/saved_objects/import/check_conflict_for_data_source.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { mockUuidv4 } from './__mocks__'; | ||
import { SavedObjectReference, SavedObjectsImportRetry } from 'opensearch-dashboards/public'; | ||
import { SavedObject } from '../types'; | ||
import { SavedObjectsErrorHelpers } from '..'; | ||
import { | ||
checkConflictsForDataSource, | ||
ConflictsForDataSourceParams, | ||
} from './check_conflict_for_data_source'; | ||
|
||
type SavedObjectType = SavedObject<{ title?: string }>; | ||
|
||
/** | ||
* Function to create a realistic-looking import object given a type and ID | ||
yujin-emma marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*/ | ||
const createObject = (type: string, id: string): SavedObjectType => ({ | ||
type, | ||
id, | ||
attributes: { title: 'some-title' }, | ||
references: (Symbol() as unknown) as SavedObjectReference[], | ||
}); | ||
|
||
const getResultMock = { | ||
conflict: (type: string, id: string) => { | ||
const error = SavedObjectsErrorHelpers.createConflictError(type, id).output.payload; | ||
return { type, id, error }; | ||
}, | ||
unresolvableConflict: (type: string, id: string) => { | ||
const conflictMock = getResultMock.conflict(type, id); | ||
const metadata = { isNotOverwritable: true }; | ||
return { ...conflictMock, error: { ...conflictMock.error, metadata } }; | ||
}, | ||
invalidType: (type: string, id: string) => { | ||
const error = SavedObjectsErrorHelpers.createUnsupportedTypeError(type).output.payload; | ||
return { type, id, error }; | ||
}, | ||
}; | ||
|
||
/** | ||
* Create a variety of different objects to exercise different import / result scenarios | ||
*/ | ||
const dataSourceObj = createObject('data-source', 'data-source-id-1'); // -> data-source type, no need to add in the filteredObjects | ||
const dataSourceObj1 = createObject('type-1', 'ds_id-1'); // -> object with data source id | ||
const dataSourceObj2 = createObject('type-2', 'ds_id-2'); // -> object with data source id | ||
const objectsWithDataSource = [dataSourceObj, dataSourceObj1, dataSourceObj2]; | ||
const dataSourceObj1Error = getResultMock.conflict(dataSourceObj1.type, dataSourceObj1.id); | ||
|
||
describe('#checkConflictsForDataSource', () => { | ||
const setupParams = (partial: { | ||
objects: SavedObjectType[]; | ||
ignoreRegularConflicts?: boolean; | ||
retries?: SavedObjectsImportRetry[]; | ||
createNewCopies?: boolean; | ||
dataSourceId?: string; | ||
}): ConflictsForDataSourceParams => { | ||
return { ...partial }; | ||
}; | ||
|
||
beforeEach(() => { | ||
mockUuidv4.mockReset(); | ||
mockUuidv4.mockReturnValueOnce(`new-object-id`); | ||
}); | ||
|
||
it('exits early if there are no objects to check', async () => { | ||
const params = setupParams({ objects: [] }); | ||
const checkConflictsForDataSourceResult = await checkConflictsForDataSource(params); | ||
expect(checkConflictsForDataSourceResult).toEqual({ | ||
filteredObjects: [], | ||
errors: [], | ||
importIdMap: new Map(), | ||
pendingOverwrites: new Set(), | ||
}); | ||
}); | ||
|
||
it('return obj if it is not data source obj and there is no conflict of the data source id', async () => { | ||
const params = setupParams({ objects: objectsWithDataSource, dataSourceId: 'ds' }); | ||
const checkConflictsForDataSourceResult = await checkConflictsForDataSource(params); | ||
expect(checkConflictsForDataSourceResult).toEqual({ | ||
filteredObjects: [dataSourceObj1, dataSourceObj2], | ||
errors: [], | ||
importIdMap: new Map(), | ||
pendingOverwrites: new Set(), | ||
}); | ||
}); | ||
|
||
it('can resolve the data source id conflict when the ds it not match when ignoreRegularConflicts=true', async () => { | ||
yujin-emma marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const params = setupParams({ | ||
objects: objectsWithDataSource, | ||
ignoreRegularConflicts: true, | ||
dataSourceId: 'currentDsId', | ||
}); | ||
const checkConflictsForDataSourceResult = await checkConflictsForDataSource(params); | ||
|
||
expect(checkConflictsForDataSourceResult).toEqual( | ||
expect.objectContaining({ | ||
filteredObjects: [ | ||
{ | ||
...dataSourceObj1, | ||
id: 'currentDsId_id-1', | ||
}, | ||
{ | ||
...dataSourceObj2, | ||
id: 'currentDsId_id-2', | ||
}, | ||
], | ||
errors: [], | ||
importIdMap: new Map([ | ||
[ | ||
`${dataSourceObj1.type}:${dataSourceObj1.id}`, | ||
{ id: 'currentDsId_id-1', omitOriginId: true }, | ||
], | ||
[ | ||
`${dataSourceObj2.type}:${dataSourceObj2.id}`, | ||
{ id: 'currentDsId_id-2', omitOriginId: true }, | ||
], | ||
]), | ||
pendingOverwrites: new Set([ | ||
`${dataSourceObj1.type}:${dataSourceObj1.id}`, | ||
`${dataSourceObj2.type}:${dataSourceObj2.id}`, | ||
]), | ||
}) | ||
); | ||
}); | ||
|
||
it('can push error when do not override with data source conflict', async () => { | ||
const params = setupParams({ | ||
objects: [dataSourceObj1], | ||
ignoreRegularConflicts: false, | ||
dataSourceId: 'currentDs', | ||
}); | ||
const checkConflictsForDataSourceResult = await checkConflictsForDataSource(params); | ||
expect(checkConflictsForDataSourceResult).toEqual({ | ||
filteredObjects: [], | ||
errors: [ | ||
{ | ||
...dataSourceObj1Error, | ||
title: dataSourceObj1.attributes.title, | ||
meta: { title: dataSourceObj1.attributes.title }, | ||
error: { type: 'conflict' }, | ||
}, | ||
], | ||
importIdMap: new Map(), | ||
pendingOverwrites: new Set(), | ||
}); | ||
}); | ||
}); |
85 changes: 85 additions & 0 deletions
85
src/core/server/saved_objects/import/check_conflict_for_data_source.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { SavedObject, SavedObjectsImportError, SavedObjectsImportRetry } from '../types'; | ||
|
||
export interface ConflictsForDataSourceParams { | ||
objects: Array<SavedObject<{ title?: string }>>; | ||
yujin-emma marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ignoreRegularConflicts?: boolean; | ||
retries?: SavedObjectsImportRetry[]; | ||
dataSourceId?: string; | ||
yujin-emma marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
interface ImportIdMapEntry { | ||
id?: string; | ||
omitOriginId?: boolean; | ||
} | ||
|
||
/** | ||
* function to check the conflict when multiple data sources are enabled. | ||
* the purpose of this function is to check the conflict of the imported saved objects and data source | ||
* @param objects, this the array of saved objects to be verified whether contains the data source conflict | ||
* @param ignoreRegularConflicts whether to override | ||
* @param retries import operations list | ||
* @param dataSourceId the id to identify the data source | ||
yujin-emma marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* @returns {filteredObjects, errors, importIdMap, pendingOverwrites } | ||
*/ | ||
export async function checkConflictsForDataSource({ | ||
objects, | ||
ignoreRegularConflicts, | ||
retries = [], | ||
dataSourceId, | ||
}: ConflictsForDataSourceParams) { | ||
const filteredObjects: Array<SavedObject<{ title?: string }>> = []; | ||
const errors: SavedObjectsImportError[] = []; | ||
const importIdMap = new Map<string, ImportIdMapEntry>(); | ||
const pendingOverwrites = new Set<string>(); | ||
|
||
// exit early if there are no objects to check | ||
if (objects.length === 0) { | ||
return { filteredObjects, errors, importIdMap, pendingOverwrites }; | ||
} | ||
const retryMap = retries.reduce( | ||
(acc, cur) => acc.set(`${cur.type}:${cur.id}`, cur), | ||
new Map<string, SavedObjectsImportRetry>() | ||
); | ||
objects.forEach((object) => { | ||
const { | ||
type, | ||
id, | ||
attributes: { title }, | ||
} = object; | ||
const { destinationId } = retryMap.get(`${type}:${id}`) || {}; | ||
|
||
if (object.type !== 'data-source') { | ||
const parts = id.split('_'); // this is the array to host the split results of the id | ||
const previoudDataSourceId = parts.length > 1 ? parts[0] : undefined; | ||
const rawId = previoudDataSourceId ? parts[1] : parts[0]; | ||
|
||
/** | ||
* for import saved object from osd exported | ||
* when the imported saved objects with the different dataSourceId comparing to the current dataSourceId | ||
*/ | ||
|
||
if ( | ||
previoudDataSourceId && | ||
previoudDataSourceId !== dataSourceId && | ||
!ignoreRegularConflicts | ||
) { | ||
const error = { type: 'conflict' as 'conflict', ...(destinationId && { destinationId }) }; | ||
errors.push({ type, id, title, meta: { title }, error }); | ||
} else if (previoudDataSourceId && previoudDataSourceId === dataSourceId) { | ||
filteredObjects.push(object); | ||
} else { | ||
const omitOriginId = ignoreRegularConflicts; | ||
importIdMap.set(`${type}:${id}`, { id: `${dataSourceId}_${rawId}`, omitOriginId }); | ||
pendingOverwrites.add(`${type}:${id}`); | ||
filteredObjects.push({ ...object, id: `${dataSourceId}_${rawId}` }); | ||
} | ||
} | ||
}); | ||
|
||
return { filteredObjects, errors, importIdMap, pendingOverwrites }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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: let's revert this file. It is not related to our change.