"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.deleteKibanaSavedObjectsAssets = deleteKibanaSavedObjectsAssets; exports.removeInstallation = removeInstallation; var _boom = _interopRequireDefault(require("@hapi/boom")); var _server = require("@kbn/core/server"); var _constants = require("@kbn/spaces-plugin/common/constants"); var _update_settings = require("../elasticsearch/index/update_settings"); var _constants2 = require("../../../constants"); var _types = require("../../../types"); var _ingest_pipeline = require("../elasticsearch/ingest_pipeline"); var _install = require("../kibana/index_pattern/install"); var _remove = require("../elasticsearch/transform/remove"); var _ml_model = require("../elasticsearch/ml_model"); var _ = require("../.."); var _archive = require("../archive"); var _remove2 = require("../elasticsearch/datastream_ilm/remove"); var _storage = require("../archive/storage"); var _audit_logging = require("../../audit_logging"); var _populate_package_policy_assigned_agents_count = require("../../package_policies/populate_package_policy_assigned_agents_count"); var _2 = require("."); /* * 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; you may not use this file except in compliance with the Elastic License * 2.0. */ async function removeInstallation(options) { const { savedObjectsClient, pkgName, pkgVersion, esClient } = options; const installation = await (0, _2.getInstallation)({ savedObjectsClient, pkgName }); if (!installation) throw _boom.default.badRequest(`${pkgName} is not installed`); const { total, items } = await _.packagePolicyService.list(savedObjectsClient, { kuery: `${_constants2.PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:${pkgName}`, page: 1, perPage: _constants2.SO_SEARCH_LIMIT }); if (!options.force) { await (0, _populate_package_policy_assigned_agents_count.populatePackagePolicyAssignedAgentsCount)(esClient, items); } if (total > 0) { if (options.force || items.every(item => { var _item$agents; return ((_item$agents = item.agents) !== null && _item$agents !== void 0 ? _item$agents : 0) === 0; })) { // delete package policies const ids = items.map(item => item.id); _.appContextService.getLogger().info(`deleting package policies of ${pkgName} package because not used by agents or force flag was enabled: ${ids}`); await _.packagePolicyService.delete(savedObjectsClient, esClient, ids, { force: options.force }); } else { throw _boom.default.badRequest(`unable to remove package with existing package policy(s) in use by agent(s)`); } } // Delete the installed assets. Don't include installation.package_assets. Those are irrelevant to users const installedAssets = [...installation.installed_kibana, ...installation.installed_es]; await deleteAssets(installation, savedObjectsClient, esClient); // Delete the manager saved object with references to the asset objects // could also update with [] or some other state _audit_logging.auditLoggingService.writeCustomSoAuditLog({ action: 'delete', id: pkgName, savedObjectType: _constants2.PACKAGES_SAVED_OBJECT_TYPE }); await savedObjectsClient.delete(_constants2.PACKAGES_SAVED_OBJECT_TYPE, pkgName); // delete the index patterns if no packages are installed // this must be done after deleting the saved object for the current package otherwise it will retrieve the package // from the registry again and keep the index patterns await (0, _install.removeUnusedIndexPatterns)(savedObjectsClient); // remove the package archive and its contents from the cache so that a reinstall fetches // a fresh copy from the registry (0, _archive.deletePackageCache)({ name: pkgName, version: pkgVersion }); await (0, _storage.removeArchiveEntries)({ savedObjectsClient, refs: installation.package_assets }); // successful delete's in SO client return {}. return something more useful return installedAssets; } async function deleteKibanaAssets(installedObjects, spaceId = _constants.DEFAULT_SPACE_ID) { const savedObjectsClient = new _server.SavedObjectsClient(_.appContextService.getSavedObjects().createInternalRepository()); const namespace = _server.SavedObjectsUtils.namespaceStringToId(spaceId); const { resolved_objects: resolvedObjects } = await savedObjectsClient.bulkResolve(installedObjects, { namespace }); for (const { saved_object: savedObject } of resolvedObjects) { _audit_logging.auditLoggingService.writeCustomSoAuditLog({ action: 'get', id: savedObject.id, savedObjectType: savedObject.type }); } const foundObjects = resolvedObjects.filter(({ saved_object: savedObject }) => { var _savedObject$error; return (savedObject === null || savedObject === void 0 ? void 0 : (_savedObject$error = savedObject.error) === null || _savedObject$error === void 0 ? void 0 : _savedObject$error.statusCode) !== 404; }); // in the case of a partial install, it is expected that some assets will be not found // we filter these out before calling delete const assetsToDelete = foundObjects.map(({ saved_object: { id, type } }) => ({ id, type })); for (const asset of assetsToDelete) { _audit_logging.auditLoggingService.writeCustomSoAuditLog({ action: 'delete', id: asset.id, savedObjectType: asset.type }); } return savedObjectsClient.bulkDelete(assetsToDelete, { namespace }); } function deleteESAssets(installedObjects, esClient) { return installedObjects.map(async ({ id, type }) => { const assetType = type; if (assetType === _types.ElasticsearchAssetType.ingestPipeline) { return (0, _ingest_pipeline.deletePipeline)(esClient, id); } else if (assetType === _types.ElasticsearchAssetType.indexTemplate) { return deleteIndexTemplate(esClient, id); } else if (assetType === _types.ElasticsearchAssetType.componentTemplate) { return deleteComponentTemplate(esClient, id); } else if (assetType === _types.ElasticsearchAssetType.transform) { return (0, _remove.deleteTransforms)(esClient, [id], true); } else if (assetType === _types.ElasticsearchAssetType.dataStreamIlmPolicy) { return (0, _remove2.deleteIlms)(esClient, [id]); } else if (assetType === _types.ElasticsearchAssetType.ilmPolicy) { return (0, _remove2.deleteIlms)(esClient, [id]); } else if (assetType === _types.ElasticsearchAssetType.mlModel) { return (0, _ml_model.deleteMlModel)(esClient, [id]); } }); } async function deleteAssets({ installed_es: installedEs, installed_kibana: installedKibana, installed_kibana_space_id: spaceId = _constants.DEFAULT_SPACE_ID }, savedObjectsClient, esClient) { const logger = _.appContextService.getLogger(); // must unset default_pipelines settings in indices first, or pipelines associated with an index cannot not be deleted // must delete index templates first, or component templates which reference them cannot be deleted // must delete ingestPipelines first, or ml models referenced in them cannot be deleted. // separate the assets into Index Templates and other assets. const [indexTemplatesAndPipelines, indexAssets, otherAssets] = installedEs.reduce(([indexTemplateAndPipelineTypes, indexAssetTypes, otherAssetTypes], asset) => { if (asset.type === _types.ElasticsearchAssetType.indexTemplate || asset.type === _types.ElasticsearchAssetType.ingestPipeline) { indexTemplateAndPipelineTypes.push(asset); } else if (asset.type === _types.ElasticsearchAssetType.index) { indexAssetTypes.push(asset); } else { otherAssetTypes.push(asset); } return [indexTemplateAndPipelineTypes, indexAssetTypes, otherAssetTypes]; }, [[], [], []]); try { // must first unset any default pipeline associated with any existing indices // by setting empty string await Promise.all(indexAssets.map(asset => (0, _update_settings.updateIndexSettings)(esClient, asset.id, { default_pipeline: '' }))); // must delete index templates and pipelines first await Promise.all(deleteESAssets(indexTemplatesAndPipelines, esClient)); // then the other asset types await Promise.all([...deleteESAssets(otherAssets, esClient), deleteKibanaAssets(installedKibana, spaceId)]); } catch (err) { // in the rollback case, partial installs are likely, so missing assets are not an error if (!_server.SavedObjectsErrorHelpers.isNotFoundError(err)) { logger.error(err); } } } async function deleteIndexTemplate(esClient, name) { // '*' shouldn't ever appear here, but it still would delete all templates if (name && name !== '*') { try { await esClient.indices.deleteIndexTemplate({ name }, { ignore: [404] }); } catch { throw new Error(`error deleting index template ${name}`); } } } async function deleteComponentTemplate(esClient, name) { // '*' shouldn't ever appear here, but it still would delete all templates if (name && name !== '*') { try { await esClient.cluster.deleteComponentTemplate({ name }, { ignore: [404] }); } catch (error) { throw new Error(`error deleting component template ${name}`); } } } async function deleteKibanaSavedObjectsAssets({ savedObjectsClient, installedPkg }) { const { installed_kibana: installedRefs, installed_kibana_space_id: spaceId } = installedPkg.attributes; if (!installedRefs.length) return; const logger = _.appContextService.getLogger(); const assetsToDelete = installedRefs.filter(({ type }) => _2.kibanaSavedObjectTypes.includes(type)).map(({ id, type }) => ({ id, type })); try { await deleteKibanaAssets(assetsToDelete, spaceId); } catch (err) { // in the rollback case, partial installs are likely, so missing assets are not an error if (!_server.SavedObjectsErrorHelpers.isNotFoundError(err)) { logger.error(err); } } }