"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.SavedObjectsService = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _rxjs = require("rxjs"); var _operators = require("rxjs/operators"); var _std = require("@kbn/std"); var _coreSavedObjectsBaseServerInternal = require("@kbn/core-saved-objects-base-server-internal"); var _coreSavedObjectsApiServerInternal = require("@kbn/core-saved-objects-api-server-internal"); var _coreSavedObjectsMigrationServerInternal = require("@kbn/core-saved-objects-migration-server-internal"); var _coreSavedObjectsImportExportServerInternal = require("@kbn/core-saved-objects-import-export-server-internal"); var _coreSavedObjectsServer = require("@kbn/core-saved-objects-server"); var _routes = require("./routes"); var _status = require("./status"); var _object_types = require("./object_types"); var _deprecations = require("./deprecations"); var _apply_type_defaults = require("./apply_type_defaults"); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ class SavedObjectsService { constructor(coreContext) { (0, _defineProperty2.default)(this, "logger", void 0); (0, _defineProperty2.default)(this, "kibanaVersion", void 0); (0, _defineProperty2.default)(this, "setupDeps", void 0); (0, _defineProperty2.default)(this, "config", void 0); (0, _defineProperty2.default)(this, "clientFactoryProvider", void 0); (0, _defineProperty2.default)(this, "encryptionExtensionFactory", void 0); (0, _defineProperty2.default)(this, "securityExtensionFactory", void 0); (0, _defineProperty2.default)(this, "spacesExtensionFactory", void 0); (0, _defineProperty2.default)(this, "migrator$", new _rxjs.Subject()); (0, _defineProperty2.default)(this, "typeRegistry", new _coreSavedObjectsBaseServerInternal.SavedObjectTypeRegistry()); (0, _defineProperty2.default)(this, "started", false); this.coreContext = coreContext; this.logger = coreContext.logger.get('savedobjects-service'); this.kibanaVersion = (0, _std.stripVersionQualifier)(this.coreContext.env.packageInfo.version); } async setup(setupDeps) { this.logger.debug('Setting up SavedObjects service'); this.setupDeps = setupDeps; const { http, elasticsearch, coreUsageData, deprecations } = setupDeps; const savedObjectsConfig = await (0, _rxjs.firstValueFrom)(this.coreContext.configService.atPath('savedObjects')); const savedObjectsMigrationConfig = await (0, _rxjs.firstValueFrom)(this.coreContext.configService.atPath('migrations')); this.config = new _coreSavedObjectsBaseServerInternal.SavedObjectConfig(savedObjectsConfig, savedObjectsMigrationConfig); deprecations.getRegistry('savedObjects').registerDeprecations((0, _deprecations.getSavedObjectsDeprecationsProvider)({ kibanaIndex: _coreSavedObjectsServer.MAIN_SAVED_OBJECT_INDEX, savedObjectsConfig: this.config, kibanaVersion: this.kibanaVersion, typeRegistry: this.typeRegistry })); coreUsageData.registerType(this.typeRegistry); (0, _routes.registerRoutes)({ http, coreUsageData, logger: this.logger, config: this.config, migratorPromise: (0, _rxjs.firstValueFrom)(this.migrator$), kibanaIndex: _coreSavedObjectsServer.MAIN_SAVED_OBJECT_INDEX, kibanaVersion: this.kibanaVersion }); (0, _object_types.registerCoreObjectTypes)(this.typeRegistry); const skipMigration = this.config.migration.skip; return { status$: (0, _status.calculateStatus$)(skipMigration ? (0, _rxjs.of)({ status: 'completed' }) : this.migrator$.pipe((0, _operators.switchMap)(migrator => migrator.getStatus$())), elasticsearch.status$), setClientFactoryProvider: provider => { if (this.started) { throw new Error('cannot call `setClientFactoryProvider` after service startup.'); } if (this.clientFactoryProvider) { throw new Error('custom client factory is already set, and can only be set once'); } this.clientFactoryProvider = provider; }, setEncryptionExtension: factory => { if (this.started) { throw new Error('cannot call `setEncryptionExtension` after service startup.'); } if (this.encryptionExtensionFactory) { throw new Error('encryption extension is already set, and can only be set once'); } this.encryptionExtensionFactory = factory; }, setSecurityExtension: factory => { if (this.started) { throw new Error('cannot call `setSecurityExtension` after service startup.'); } if (this.securityExtensionFactory) { throw new Error('security extension is already set, and can only be set once'); } this.securityExtensionFactory = factory; }, setSpacesExtension: factory => { if (this.started) { throw new Error('cannot call `setSpacesExtension` after service startup.'); } if (this.spacesExtensionFactory) { throw new Error('spaces extension is already set, and can only be set once'); } this.spacesExtensionFactory = factory; }, registerType: type => { if (this.started) { throw new Error('cannot call `registerType` after service startup.'); } this.typeRegistry.registerType((0, _apply_type_defaults.applyTypeDefaults)(type)); }, getTypeRegistry: () => this.typeRegistry, getDefaultIndex: () => _coreSavedObjectsServer.MAIN_SAVED_OBJECT_INDEX, getAllIndices: () => [..._coreSavedObjectsServer.ALL_SAVED_OBJECT_INDICES] }; } async start({ elasticsearch, pluginsInitialized = true, docLinks, node }) { if (!this.setupDeps || !this.config) { throw new Error('#setup() needs to be run first'); } this.logger.debug('Starting SavedObjects service'); const client = elasticsearch.client; const waitForMigrationCompletion = node.roles.backgroundTasks && !node.roles.ui; const migrator = this.createMigrator(this.config.migration, elasticsearch.client.asInternalUser, docLinks, waitForMigrationCompletion, node); this.migrator$.next(migrator); /** * Note: We want to ensure that migrations have completed before * continuing with further Core start steps that might use SavedObjects * such as running the legacy server, legacy plugins and allowing incoming * HTTP requests. * * However, our build system optimize step and some tests depend on the * HTTP server running without an Elasticsearch server being available. * So, when the `migrations.skip` is true, we skip migrations altogether. * * We also cannot safely run migrations if plugins are not initialized since * not plugin migrations won't be registered. */ const skipMigrations = this.config.migration.skip || !pluginsInitialized; /** * Note: Prepares all migrations maps. If a saved object type was registered with property `migrations` * of type function; this function will be called to get the type's SavedObjectMigrationMap. */ migrator.prepareMigrations(); if (skipMigrations) { this.logger.warn('Skipping Saved Object migrations on startup. Note: Individual documents will still be migrated when read or written.'); } else { this.logger.info('Waiting until all Elasticsearch nodes are compatible with Kibana before starting saved objects migrations...'); // The Elasticsearch service should already ensure that, but let's double check just in case. // Should it be replaced with elasticsearch.status$ API instead? const compatibleNodes = await this.setupDeps.elasticsearch.esNodesCompatibility$.pipe((0, _operators.filter)(nodes => nodes.isCompatible), (0, _operators.take)(1)).toPromise(); // Running migrations only if we got compatible nodes. // It may happen that the observable completes due to Kibana shutting down // and the promise above fulfils as undefined. We shouldn't trigger migrations at that point. if (compatibleNodes) { this.logger.info('Starting saved objects migrations'); await migrator.runMigrations(); } } const createRepository = (esClient, includedHiddenTypes = [], extensions) => { return _coreSavedObjectsApiServerInternal.SavedObjectsRepository.createRepository(migrator, this.typeRegistry, _coreSavedObjectsServer.MAIN_SAVED_OBJECT_INDEX, esClient, this.logger.get('repository'), includedHiddenTypes, extensions); }; const repositoryFactory = { createInternalRepository: (includedHiddenTypes, extensions) => createRepository(client.asInternalUser, includedHiddenTypes, extensions), createScopedRepository: (req, includedHiddenTypes, extensions) => createRepository(client.asScoped(req).asCurrentUser, includedHiddenTypes, extensions) }; const clientProvider = new _coreSavedObjectsApiServerInternal.SavedObjectsClientProvider({ defaultClientFactory({ request, includedHiddenTypes, extensions }) { const repository = repositoryFactory.createScopedRepository(request, includedHiddenTypes, extensions); return new _coreSavedObjectsApiServerInternal.SavedObjectsClient(repository); }, typeRegistry: this.typeRegistry, encryptionExtensionFactory: this.encryptionExtensionFactory, securityExtensionFactory: this.securityExtensionFactory, spacesExtensionFactory: this.spacesExtensionFactory }); if (this.clientFactoryProvider) { const clientFactory = this.clientFactoryProvider(repositoryFactory); clientProvider.setClientFactory(clientFactory); } this.started = true; return { getScopedClient: clientProvider.getClient.bind(clientProvider), createScopedRepository: repositoryFactory.createScopedRepository, createInternalRepository: repositoryFactory.createInternalRepository, createSerializer: () => new _coreSavedObjectsBaseServerInternal.SavedObjectsSerializer(this.typeRegistry), createExporter: savedObjectsClient => new _coreSavedObjectsImportExportServerInternal.SavedObjectsExporter({ savedObjectsClient, typeRegistry: this.typeRegistry, exportSizeLimit: this.config.maxImportExportSize, logger: this.logger.get('exporter') }), createImporter: (savedObjectsClient, options) => { var _options$importSizeLi; return new _coreSavedObjectsImportExportServerInternal.SavedObjectsImporter({ savedObjectsClient, typeRegistry: this.typeRegistry, importSizeLimit: (_options$importSizeLi = options === null || options === void 0 ? void 0 : options.importSizeLimit) !== null && _options$importSizeLi !== void 0 ? _options$importSizeLi : this.config.maxImportExportSize }); }, getTypeRegistry: () => this.typeRegistry, getDefaultIndex: () => _coreSavedObjectsServer.MAIN_SAVED_OBJECT_INDEX, getIndexForType: type => { var _definition$indexPatt; const definition = this.typeRegistry.getType(type); return (_definition$indexPatt = definition === null || definition === void 0 ? void 0 : definition.indexPattern) !== null && _definition$indexPatt !== void 0 ? _definition$indexPatt : _coreSavedObjectsServer.MAIN_SAVED_OBJECT_INDEX; }, getIndicesForTypes: types => { const indices = new Set(); types.forEach(type => { var _definition$indexPatt2; const definition = this.typeRegistry.getType(type); const index = (_definition$indexPatt2 = definition === null || definition === void 0 ? void 0 : definition.indexPattern) !== null && _definition$indexPatt2 !== void 0 ? _definition$indexPatt2 : _coreSavedObjectsServer.MAIN_SAVED_OBJECT_INDEX; indices.add(index); }); return [...indices]; }, getAllIndices: () => [..._coreSavedObjectsServer.ALL_SAVED_OBJECT_INDICES] }; } async stop() {} createMigrator(soMigrationsConfig, client, docLinks, waitForMigrationCompletion, nodeInfo) { return new _coreSavedObjectsMigrationServerInternal.KibanaMigrator({ typeRegistry: this.typeRegistry, logger: this.logger, kibanaVersion: this.kibanaVersion, soMigrationsConfig, kibanaIndex: _coreSavedObjectsServer.MAIN_SAVED_OBJECT_INDEX, defaultIndexTypesMap: _coreSavedObjectsBaseServerInternal.DEFAULT_INDEX_TYPES_MAP, client, docLinks, waitForMigrationCompletion, nodeRoles: nodeInfo.roles }); } } exports.SavedObjectsService = SavedObjectsService;