Skip to content

Commit

Permalink
[Workspace] Add workspaces parameters to all saved objects API
Browse files Browse the repository at this point in the history
Signed-off-by: gaobinlong <gbinlong@amazon.com>
  • Loading branch information
gaobinlong authored and SuZhou-Joe committed Sep 29, 2023
1 parent 34a8594 commit 8cd7c8c
Show file tree
Hide file tree
Showing 26 changed files with 258 additions and 18 deletions.
1 change: 1 addition & 0 deletions src/core/public/saved_objects/saved_objects_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ export class SavedObjectsClient {
filter: 'filter',
namespaces: 'namespaces',
preference: 'preference',
workspaces: 'workspaces',
};

const renamedQuery = renameKeys<SavedObjectsFindOptions, any>(renameMap, options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ describe('getSortedObjectsForExport()', () => {
index-pattern,
search,
],
workspaces: undefined,
},
],
],
Expand Down Expand Up @@ -218,6 +219,7 @@ describe('getSortedObjectsForExport()', () => {
index-pattern,
search,
],
workspaces: undefined,
},
],
],
Expand Down Expand Up @@ -368,6 +370,7 @@ describe('getSortedObjectsForExport()', () => {
index-pattern,
search,
],
workspaces: undefined,
},
],
],
Expand Down Expand Up @@ -459,6 +462,7 @@ describe('getSortedObjectsForExport()', () => {
index-pattern,
search,
],
workspaces: undefined,
},
],
],
Expand Down Expand Up @@ -666,6 +670,7 @@ describe('getSortedObjectsForExport()', () => {
],
Object {
namespace: undefined,
workspaces: undefined,
},
],
],
Expand Down Expand Up @@ -784,6 +789,7 @@ describe('getSortedObjectsForExport()', () => {
],
Object {
namespace: undefined,
workspaces: undefined,
},
],
Array [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ export interface SavedObjectsExportOptions {
excludeExportDetails?: boolean;
/** optional namespace to override the namespace used by the savedObjectsClient. */
namespace?: string;
/** optional workspaces to override the workspaces used by the savedObjectsClient. */
workspaces?: string[];
}

/**
Expand Down Expand Up @@ -87,13 +89,15 @@ async function fetchObjectsToExport({
exportSizeLimit,
savedObjectsClient,
namespace,
workspaces,
}: {
objects?: SavedObjectsExportOptions['objects'];
types?: string[];
search?: string;
exportSizeLimit: number;
savedObjectsClient: SavedObjectsClientContract;
namespace?: string;
workspaces?: string[];
}) {
if ((types?.length ?? 0) > 0 && (objects?.length ?? 0) > 0) {
throw Boom.badRequest(`Can't specify both "types" and "objects" properties when exporting`);
Expand All @@ -105,7 +109,7 @@ async function fetchObjectsToExport({
if (typeof search === 'string') {
throw Boom.badRequest(`Can't specify both "search" and "objects" properties when exporting`);
}
const bulkGetResult = await savedObjectsClient.bulkGet(objects, { namespace });
const bulkGetResult = await savedObjectsClient.bulkGet(objects, { namespace, workspaces });
const erroredObjects = bulkGetResult.saved_objects.filter((obj) => !!obj.error);
if (erroredObjects.length) {
const err = Boom.badRequest();
Expand All @@ -121,6 +125,7 @@ async function fetchObjectsToExport({
search,
perPage: exportSizeLimit,
namespaces: namespace ? [namespace] : undefined,
workspaces,
});
if (findResponse.total > exportSizeLimit) {
throw Boom.badRequest(`Can't export more than ${exportSizeLimit} objects`);
Expand Down Expand Up @@ -153,6 +158,7 @@ export async function exportSavedObjectsToStream({
includeReferencesDeep = false,
excludeExportDetails = false,
namespace,
workspaces,
}: SavedObjectsExportOptions) {
const rootObjects = await fetchObjectsToExport({
types,
Expand All @@ -161,6 +167,7 @@ export async function exportSavedObjectsToStream({
savedObjectsClient,
exportSizeLimit,
namespace,
workspaces,
});
let exportedObjects: Array<SavedObject<unknown>> = [];
let missingReferences: SavedObjectsExportResultDetails['missingReferences'] = [];
Expand Down
3 changes: 3 additions & 0 deletions src/core/server/saved_objects/import/check_conflicts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ interface CheckConflictsParams {
ignoreRegularConflicts?: boolean;
retries?: SavedObjectsImportRetry[];
createNewCopies?: boolean;
workspaces?: string[];
}

const isUnresolvableConflict = (error: SavedObjectError) =>
Expand All @@ -56,6 +57,7 @@ export async function checkConflicts({
ignoreRegularConflicts,
retries = [],
createNewCopies,
workspaces,
}: CheckConflictsParams) {
const filteredObjects: Array<SavedObject<{ title?: string }>> = [];
const errors: SavedObjectsImportError[] = [];
Expand All @@ -77,6 +79,7 @@ export async function checkConflicts({
});
const checkConflictsResult = await savedObjectsClient.checkConflicts(objectsToCheck, {
namespace,
workspaces,
});
const errorMap = checkConflictsResult.errors.reduce(
(acc, { type, id, error }) => acc.set(`${type}:${id}`, error),
Expand Down
5 changes: 4 additions & 1 deletion src/core/server/saved_objects/import/create_saved_objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ interface CreateSavedObjectsParams<T> {
importIdMap: Map<string, { id?: string; omitOriginId?: boolean }>;
namespace?: string;
overwrite?: boolean;
workspaces?: string[];
}
interface CreateSavedObjectsResult<T> {
createdObjects: Array<CreatedObject<T>>;
Expand All @@ -56,6 +57,7 @@ export const createSavedObjects = async <T>({
importIdMap,
namespace,
overwrite,
workspaces,
}: CreateSavedObjectsParams<T>): Promise<CreateSavedObjectsResult<T>> => {
// filter out any objects that resulted in errors
const errorSet = accumulatedErrors.reduce(
Expand Down Expand Up @@ -103,14 +105,15 @@ export const createSavedObjects = async <T>({
const bulkCreateResponse = await savedObjectsClient.bulkCreate(objectsToCreate, {
namespace,
overwrite,
workspaces,
});
expectedResults = bulkCreateResponse.saved_objects;
}

// remap results to reflect the object IDs that were submitted for import
// this ensures that consumers understand the results
const remappedResults = expectedResults.map<CreatedObject<T>>((result) => {
const { id } = objectIdMap.get(`${result.type}:${result.id}`)!;
const { id } = objectIdMap.get(`${result.type}:${result.id}`) || ({} as SavedObject<T>);
// also, include a `destinationId` field if the object create attempt was made with a different ID
return { ...result, id, ...(id !== result.id && { destinationId: result.id }) };
});
Expand Down
2 changes: 2 additions & 0 deletions src/core/server/saved_objects/import/import_saved_objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export async function importSavedObjectsFromStream({
savedObjectsClient,
typeRegistry,
namespace,
workspaces,
}: SavedObjectsImportOptions): Promise<SavedObjectsImportResponse> {
let errorAccumulator: SavedObjectsImportError[] = [];
const supportedTypes = typeRegistry.getImportableAndExportableTypes().map((type) => type.name);
Expand Down Expand Up @@ -118,6 +119,7 @@ export async function importSavedObjectsFromStream({
importIdMap,
overwrite,
namespace,
workspaces,
};
const createSavedObjectsResult = await createSavedObjects(createSavedObjectsParams);
errorAccumulator = [...errorAccumulator, ...createSavedObjectsResult.errors];
Expand Down
2 changes: 2 additions & 0 deletions src/core/server/saved_objects/import/resolve_import_errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export async function resolveSavedObjectsImportErrors({
typeRegistry,
namespace,
createNewCopies,
workspaces,
}: SavedObjectsResolveImportErrorsOptions): Promise<SavedObjectsImportResponse> {
// throw a BadRequest error if we see invalid retries
validateRetries(retries);
Expand Down Expand Up @@ -157,6 +158,7 @@ export async function resolveSavedObjectsImportErrors({
importIdMap,
namespace,
overwrite,
workspaces,
};
const { createdObjects, errors: bulkCreateErrors } = await createSavedObjects(
createSavedObjectsParams
Expand Down
4 changes: 4 additions & 0 deletions src/core/server/saved_objects/import/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ export interface SavedObjectsImportOptions {
namespace?: string;
/** If true, will create new copies of import objects, each with a random `id` and undefined `originId`. */
createNewCopies: boolean;
/** if specified, will import in given workspaces, else will import as global object */
workspaces?: string[];
}

/**
Expand All @@ -208,6 +210,8 @@ export interface SavedObjectsResolveImportErrorsOptions {
namespace?: string;
/** If true, will create new copies of import objects, each with a random `id` and undefined `originId`. */
createNewCopies: boolean;
/** if specified, will import in given workspaces, else will import as global object */
workspaces?: string[];
}

export type CreatedObject<T> = SavedObject<T> & { destinationId?: string };

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ function defaultMapping(): IndexMapping {
},
},
},
workspaces: {
type: 'keyword',
},
},
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ describe('IndexMigrator', () => {
references: '7997cf5a56cc02bdc9c93361bde732b0',
type: '2f4316de49999235636386fe51dc06c1',
updated_at: '00da57df13e94e9d98437d13ace4bfe0',
workspaces: '2f4316de49999235636386fe51dc06c1',
},
},
properties: {
Expand All @@ -92,6 +93,9 @@ describe('IndexMigrator', () => {
originId: { type: 'keyword' },
type: { type: 'keyword' },
updated_at: { type: 'date' },
workspaces: {
type: 'keyword',
},
references: {
type: 'nested',
properties: {
Expand Down Expand Up @@ -199,6 +203,7 @@ describe('IndexMigrator', () => {
references: '7997cf5a56cc02bdc9c93361bde732b0',
type: '2f4316de49999235636386fe51dc06c1',
updated_at: '00da57df13e94e9d98437d13ace4bfe0',
workspaces: '2f4316de49999235636386fe51dc06c1',
},
},
properties: {
Expand All @@ -210,6 +215,9 @@ describe('IndexMigrator', () => {
originId: { type: 'keyword' },
type: { type: 'keyword' },
updated_at: { type: 'date' },
workspaces: {
type: 'keyword',
},
references: {
type: 'nested',
properties: {
Expand Down Expand Up @@ -260,6 +268,7 @@ describe('IndexMigrator', () => {
references: '7997cf5a56cc02bdc9c93361bde732b0',
type: '2f4316de49999235636386fe51dc06c1',
updated_at: '00da57df13e94e9d98437d13ace4bfe0',
workspaces: '2f4316de49999235636386fe51dc06c1',
},
},
properties: {
Expand All @@ -271,6 +280,9 @@ describe('IndexMigrator', () => {
originId: { type: 'keyword' },
type: { type: 'keyword' },
updated_at: { type: 'date' },
workspaces: {
type: 'keyword',
},
references: {
type: 'nested',
properties: {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 11 additions & 1 deletion src/core/server/saved_objects/routes/bulk_create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ export const registerBulkCreateRoute = (router: IRouter) => {
validate: {
query: schema.object({
overwrite: schema.boolean({ defaultValue: false }),
workspaces: schema.maybe(
schema.oneOf([schema.string(), schema.arrayOf(schema.string())])
),
}),
body: schema.arrayOf(
schema.object({
Expand All @@ -62,7 +65,14 @@ export const registerBulkCreateRoute = (router: IRouter) => {
},
router.handleLegacyErrors(async (context, req, res) => {
const { overwrite } = req.query;
const result = await context.core.savedObjects.client.bulkCreate(req.body, { overwrite });
let workspaces = req.query.workspaces;
if (typeof workspaces === 'string') {
workspaces = [workspaces];
}
const result = await context.core.savedObjects.client.bulkCreate(req.body, {
overwrite,
workspaces,
});
return res.ok({ body: result });
})
);
Expand Down
12 changes: 10 additions & 2 deletions src/core/server/saved_objects/routes/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,23 @@ export const registerCreateRoute = (router: IRouter) => {
)
),
initialNamespaces: schema.maybe(schema.arrayOf(schema.string(), { minSize: 1 })),
workspaces: schema.maybe(schema.arrayOf(schema.string(), { minSize: 1 })),
}),
},
},
router.handleLegacyErrors(async (context, req, res) => {
const { type, id } = req.params;
const { overwrite } = req.query;
const { attributes, migrationVersion, references, initialNamespaces } = req.body;
const { attributes, migrationVersion, references, initialNamespaces, workspaces } = req.body;

const options = { id, overwrite, migrationVersion, references, initialNamespaces };
const options = {
id,
overwrite,
migrationVersion,
references,
initialNamespaces,
workspaces,
};
const result = await context.core.savedObjects.client.create(type, attributes, options);
return res.ok({ body: result });
})
Expand Down
Loading

0 comments on commit 8cd7c8c

Please sign in to comment.