From acddbc0c6a39a3eb3e16ae31abbc2b423c3764b2 Mon Sep 17 00:00:00 2001 From: gaobinlong Date: Wed, 28 Feb 2024 16:57:53 +0800 Subject: [PATCH] Make osd system index's mappings extendable for plugins Signed-off-by: gaobinlong --- src/core/server/legacy/legacy_service.ts | 2 ++ src/core/server/plugins/plugin_context.ts | 1 + .../migrations/core/build_active_mappings.ts | 31 ++++------------- .../migrations/core/migration_context.ts | 13 ++++++-- .../opensearch_dashboards_migrator.ts | 13 ++++++-- .../saved_objects/saved_objects_service.ts | 15 ++++++++- src/plugins/workspace/server/plugin.ts | 33 +++++++++++++++++++ 7 files changed, 77 insertions(+), 31 deletions(-) diff --git a/src/core/server/legacy/legacy_service.ts b/src/core/server/legacy/legacy_service.ts index 4dec545fd186..d7c18d56b7d0 100644 --- a/src/core/server/legacy/legacy_service.ts +++ b/src/core/server/legacy/legacy_service.ts @@ -280,6 +280,8 @@ export class LegacyService implements CoreService { setStatus: () => { throw new Error(`core.savedObjects.setStatus is unsupported in legacy`); }, + addExtendedSavedObjectsMappings: + setupDeps.core.savedObjects.addExtendedSavedObjectsMappings, }, status: { isStatusPageAnonymous: setupDeps.core.status.isStatusPageAnonymous, diff --git a/src/core/server/plugins/plugin_context.ts b/src/core/server/plugins/plugin_context.ts index c0eb5b29bb63..53d590107bdc 100644 --- a/src/core/server/plugins/plugin_context.ts +++ b/src/core/server/plugins/plugin_context.ts @@ -206,6 +206,7 @@ export function createPluginSetupContext( getImportExportObjectLimit: deps.savedObjects.getImportExportObjectLimit, setRepositoryFactoryProvider: deps.savedObjects.setRepositoryFactoryProvider, setStatus: deps.savedObjects.setStatus, + addExtendedSavedObjectsMappings: deps.savedObjects.addExtendedSavedObjectsMappings, }, status: { core$: deps.status.core$, diff --git a/src/core/server/saved_objects/migrations/core/build_active_mappings.ts b/src/core/server/saved_objects/migrations/core/build_active_mappings.ts index 05fb534f7a11..96c729cdabdc 100644 --- a/src/core/server/saved_objects/migrations/core/build_active_mappings.ts +++ b/src/core/server/saved_objects/migrations/core/build_active_mappings.ts @@ -36,7 +36,6 @@ import crypto from 'crypto'; import { cloneDeep, mapValues } from 'lodash'; import { IndexMapping, - SavedObjectsFieldMapping, SavedObjectsMappingProperties, SavedObjectsTypeMappingDefinitions, } from './../../mappings'; @@ -48,11 +47,15 @@ import { * @param typeDefinitions - the type definitions to build mapping from. */ export function buildActiveMappings( - typeDefinitions: SavedObjectsTypeMappingDefinitions | SavedObjectsMappingProperties + typeDefinitions: SavedObjectsTypeMappingDefinitions | SavedObjectsMappingProperties, + extendedMappings?: SavedObjectsMappingProperties ): IndexMapping { const mapping = defaultMapping(); - const mergedProperties = validateAndMerge(mapping.properties, typeDefinitions); + let mergedProperties = validateAndMerge(mapping.properties, typeDefinitions); + if (extendedMappings) { + mergedProperties = validateAndMerge(mergedProperties, extendedMappings); + } return cloneDeep({ ...mapping, @@ -138,16 +141,6 @@ function findChangedProp(actual: any, expected: any) { * @returns {IndexMapping} */ function defaultMapping(): IndexMapping { - const principals: SavedObjectsFieldMapping = { - properties: { - users: { - type: 'keyword', - }, - groups: { - type: 'keyword', - }, - }, - }; return { dynamic: 'strict', properties: { @@ -186,18 +179,6 @@ function defaultMapping(): IndexMapping { }, }, }, - workspaces: { - type: 'keyword', - }, - permissions: { - properties: { - read: principals, - write: principals, - management: principals, - library_read: principals, - library_write: principals, - }, - }, }, }; } diff --git a/src/core/server/saved_objects/migrations/core/migration_context.ts b/src/core/server/saved_objects/migrations/core/migration_context.ts index 82001f7ed4c4..78908730e9fa 100644 --- a/src/core/server/saved_objects/migrations/core/migration_context.ts +++ b/src/core/server/saved_objects/migrations/core/migration_context.ts @@ -59,6 +59,7 @@ export interface MigrationOpts { documentMigrator: VersionedTransformer; serializer: SavedObjectsSerializer; convertToAliasScript?: string; + extendedMappingProperties?: SavedObjectsMappingProperties; /** * If specified, templates matching the specified pattern will be removed @@ -93,7 +94,12 @@ export async function migrationContext(opts: MigrationOpts): Promise { const { log, client } = opts; const alias = opts.index; const source = createSourceContext(await Index.fetchInfo(client, alias), alias); - const dest = createDestContext(source, alias, opts.mappingProperties); + const dest = createDestContext( + source, + alias, + opts.mappingProperties, + opts.extendedMappingProperties + ); return { client, @@ -125,10 +131,11 @@ function createSourceContext(source: Index.FullIndexInfo, alias: string) { function createDestContext( source: Index.FullIndexInfo, alias: string, - typeMappingDefinitions: SavedObjectsTypeMappingDefinitions + typeMappingDefinitions: SavedObjectsTypeMappingDefinitions, + extendedMappingProperties?: SavedObjectsMappingProperties ): Index.FullIndexInfo { const targetMappings = disableUnknownTypeMappingFields( - buildActiveMappings(typeMappingDefinitions), + buildActiveMappings(typeMappingDefinitions, extendedMappingProperties), source.mappings ); diff --git a/src/core/server/saved_objects/migrations/opensearch_dashboards/opensearch_dashboards_migrator.ts b/src/core/server/saved_objects/migrations/opensearch_dashboards/opensearch_dashboards_migrator.ts index 284615083af3..4a138ce0ba17 100644 --- a/src/core/server/saved_objects/migrations/opensearch_dashboards/opensearch_dashboards_migrator.ts +++ b/src/core/server/saved_objects/migrations/opensearch_dashboards/opensearch_dashboards_migrator.ts @@ -37,7 +37,11 @@ import { OpenSearchDashboardsConfigType } from 'src/core/server/opensearch_dashb import { BehaviorSubject } from 'rxjs'; import { Logger } from '../../../logging'; -import { IndexMapping, SavedObjectsTypeMappingDefinitions } from '../../mappings'; +import { + IndexMapping, + SavedObjectsMappingProperties, + SavedObjectsTypeMappingDefinitions, +} from '../../mappings'; import { SavedObjectUnsanitizedDoc, SavedObjectsSerializer } from '../../serialization'; import { buildActiveMappings, IndexMigrator, MigrationResult, MigrationStatus } from '../core'; import { DocumentMigrator, VersionedTransformer } from '../core/document_migrator'; @@ -54,6 +58,7 @@ export interface OpenSearchDashboardsMigratorOptions { opensearchDashboardsConfig: OpenSearchDashboardsConfigType; opensearchDashboardsVersion: string; logger: Logger; + extendedSavedObjectsMappings?: SavedObjectsMappingProperties; } export type IOpenSearchDashboardsMigrator = Pick< @@ -83,6 +88,7 @@ export class OpenSearchDashboardsMigrator { status: 'waiting', }); private readonly activeMappings: IndexMapping; + private readonly extendedMappingProperties?: SavedObjectsMappingProperties; /** * Creates an instance of OpenSearchDashboardsMigrator. @@ -93,6 +99,7 @@ export class OpenSearchDashboardsMigrator { opensearchDashboardsConfig, savedObjectsConfig, opensearchDashboardsVersion, + extendedSavedObjectsMappings, logger, }: OpenSearchDashboardsMigratorOptions) { this.client = client; @@ -101,6 +108,7 @@ export class OpenSearchDashboardsMigrator { this.typeRegistry = typeRegistry; this.serializer = new SavedObjectsSerializer(this.typeRegistry); this.mappingProperties = mergeTypes(this.typeRegistry.getAllTypes()); + this.extendedMappingProperties = extendedSavedObjectsMappings; this.log = logger; this.documentMigrator = new DocumentMigrator({ opensearchDashboardsVersion, @@ -109,7 +117,7 @@ export class OpenSearchDashboardsMigrator { }); // Building the active mappings (and associated md5sums) is an expensive // operation so we cache the result - this.activeMappings = buildActiveMappings(this.mappingProperties); + this.activeMappings = buildActiveMappings(this.mappingProperties, extendedSavedObjectsMappings); } /** @@ -172,6 +180,7 @@ export class OpenSearchDashboardsMigrator { index, log: this.log, mappingProperties: indexMap[index].typeMappings, + extendedMappingProperties: this.extendedMappingProperties, pollInterval: this.savedObjectsConfig.pollInterval, scrollDuration: this.savedObjectsConfig.scrollDuration, serializer: this.serializer, diff --git a/src/core/server/saved_objects/saved_objects_service.ts b/src/core/server/saved_objects/saved_objects_service.ts index 64c8b6a5fbc8..4bdc34d16e71 100644 --- a/src/core/server/saved_objects/saved_objects_service.ts +++ b/src/core/server/saved_objects/saved_objects_service.ts @@ -37,6 +37,7 @@ import { SavedObjectsClient, SavedObjectsClientProvider, SavedObjectsClientProviderOptions, + SavedObjectsMappingProperties, } from './'; import { OpenSearchDashboardsMigrator, IOpenSearchDashboardsMigrator } from './migrations'; import { CoreContext } from '../core_context'; @@ -183,6 +184,11 @@ export interface SavedObjectsServiceSetup { * Completely overrides the default status. */ setStatus(status$: Observable>): void; + + /** + * Allow a plugin to add extended saved objects mappings + */ + addExtendedSavedObjectsMappings: (mappings: SavedObjectsMappingProperties) => void; } /** @@ -314,6 +320,7 @@ export class SavedObjectsService level: ServiceStatusLevels.unavailable, summary: `waiting`, }); + private extendedSavedObjectsMappings?: SavedObjectsMappingProperties; constructor(private readonly coreContext: CoreContext) { this.logger = coreContext.logger.get('savedobjects-service'); @@ -389,6 +396,9 @@ export class SavedObjectsService } this.savedObjectServiceCustomStatus$ = status$; }, + addExtendedSavedObjectsMappings: (mappings: SavedObjectsMappingProperties) => { + this.extendedSavedObjectsMappings = mappings; + }, }; } @@ -400,7 +410,7 @@ export class SavedObjectsService throw new Error('#setup() needs to be run first'); } - this.logger.debug('Starting SavedObjects service'); + this.logger.info('Starting SavedObjects service'); if (this.savedObjectServiceCustomStatus$) { this.savedObjectServiceCustomStatus$ @@ -435,6 +445,7 @@ export class SavedObjectsService opensearchDashboardsConfig, this.config.migration, opensearch.client, + this.extendedSavedObjectsMappings, migrationsRetryDelay ); @@ -546,6 +557,7 @@ export class SavedObjectsService opensearchDashboardsConfig: OpenSearchDashboardsConfigType, savedObjectsConfig: SavedObjectsMigrationConfigType, client: IClusterClient, + extendedSavedObjectsMappings?: SavedObjectsMappingProperties, migrationsRetryDelay?: number ): IOpenSearchDashboardsMigrator { return new OpenSearchDashboardsMigrator({ @@ -559,6 +571,7 @@ export class SavedObjectsService this.logger, migrationsRetryDelay ), + extendedSavedObjectsMappings, }); } } diff --git a/src/plugins/workspace/server/plugin.ts b/src/plugins/workspace/server/plugin.ts index edf785b4a322..1c9ded8d50b7 100644 --- a/src/plugins/workspace/server/plugin.ts +++ b/src/plugins/workspace/server/plugin.ts @@ -11,6 +11,8 @@ import { Plugin, Logger, SavedObjectsClient, + SavedObjectsMappingProperties, + SavedObjectsFieldMapping, } from '../../../core/server'; import { IWorkspaceClientImpl } from './types'; import { WorkspaceClientWithSavedObject } from './workspace_client'; @@ -62,6 +64,12 @@ export class WorkspacePlugin implements Plugin<{}, {}> { await this.client.setup(core); + let extendedSavedObjectsMappings: SavedObjectsMappingProperties = { + workspaces: { + type: 'keyword', + }, + }; + this.logger.info('Workspace permission control enabled:' + isPermissionControlEnabled); if (isPermissionControlEnabled) { this.permissionControl = new SavedObjectsPermissionControl(this.logger); @@ -80,8 +88,33 @@ export class WorkspacePlugin implements Plugin<{}, {}> { WORKSPACE_SAVED_OBJECTS_CLIENT_WRAPPER_ID, workspaceSavedObjectsClientWrapper.wrapperFactory ); + + const principals: SavedObjectsFieldMapping = { + properties: { + users: { + type: 'keyword', + }, + groups: { + type: 'keyword', + }, + }, + }; + extendedSavedObjectsMappings = { + ...extendedSavedObjectsMappings, + permissions: { + properties: { + read: principals, + write: principals, + management: principals, + library_read: principals, + library_write: principals, + }, + }, + }; } + core.savedObjects.addExtendedSavedObjectsMappings(extendedSavedObjectsMappings); + this.proxyWorkspaceTrafficToRealHandler(core); registerRoutes({