"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.handleExperimentalDatastreamFeatureOptIn = handleExperimentalDatastreamFeatureOptIn; var _lodash = require("lodash"); var _services = require("../../../common/services"); var _app_context = require("../app_context"); var _install = require("../epm/elasticsearch/template/install"); var _template = require("../epm/elasticsearch/template/template"); var _packages = require("../epm/packages"); var _update = require("../epm/packages/update"); var _experimental_datastream_features_helper = require("../experimental_datastream_features_helper"); /* * 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 handleExperimentalDatastreamFeatureOptIn({ soClient, esClient, packagePolicy }) { var _packagePolicy$packag; if (!((_packagePolicy$packag = packagePolicy.package) !== null && _packagePolicy$packag !== void 0 && _packagePolicy$packag.experimental_data_stream_features)) { return; } // If we're performing an update, we want to check if we actually need to perform // an update to the component templates for the package. So we fetch the saved object // for the package policy here to compare later. let installation; const templateMappings = {}; if (packagePolicy.package) { var _packageInfo$data_str; installation = await (0, _packages.getInstallation)({ savedObjectsClient: soClient, pkgName: packagePolicy.package.name }); const packageInfo = await (0, _packages.getPackageInfo)({ savedObjectsClient: soClient, pkgName: packagePolicy.package.name, pkgVersion: packagePolicy.package.version }); // prepare template from package spec to find original index:false values const templates = (_packageInfo$data_str = packageInfo.data_streams) === null || _packageInfo$data_str === void 0 ? void 0 : _packageInfo$data_str.map(dataStream => { var _packagePolicy$packag2, _packagePolicy$packag3; const experimentalDataStreamFeature = (_packagePolicy$packag2 = packagePolicy.package) === null || _packagePolicy$packag2 === void 0 ? void 0 : (_packagePolicy$packag3 = _packagePolicy$packag2.experimental_data_stream_features) === null || _packagePolicy$packag3 === void 0 ? void 0 : _packagePolicy$packag3.find(datastreamFeature => datastreamFeature.data_stream === (0, _services.getRegistryDataStreamAssetBaseName)(dataStream)); return (0, _install.prepareTemplate)({ pkg: packageInfo, dataStream, experimentalDataStreamFeature }); }); templates === null || templates === void 0 ? void 0 : templates.forEach(template => { Object.keys(template.componentTemplates).forEach(templateName => { var _mappings; templateMappings[templateName] = (_mappings = template.componentTemplates[templateName].template.mappings) !== null && _mappings !== void 0 ? _mappings : {}; }); }); } const updatedIndexTemplates = []; for (const featureMapEntry of packagePolicy.package.experimental_data_stream_features) { var _installation, _installation$experim, _componentTemplate$te; const existingOptIn = (_installation = installation) === null || _installation === void 0 ? void 0 : (_installation$experim = _installation.experimental_data_stream_features) === null || _installation$experim === void 0 ? void 0 : _installation$experim.find(optIn => optIn.data_stream === featureMapEntry.data_stream); const hasFeatureChanged = name => (existingOptIn === null || existingOptIn === void 0 ? void 0 : existingOptIn.features[name]) !== featureMapEntry.features[name]; const isSyntheticSourceOptInChanged = hasFeatureChanged('synthetic_source'); const isTSDBOptInChanged = hasFeatureChanged('tsdb'); const isDocValueOnlyNumericChanged = hasFeatureChanged('doc_value_only_numeric'); const isDocValueOnlyOtherChanged = hasFeatureChanged('doc_value_only_other'); if ([isSyntheticSourceOptInChanged, isTSDBOptInChanged, isDocValueOnlyNumericChanged, isDocValueOnlyOtherChanged].every(hasFlagChange => !hasFlagChange)) continue; const componentTemplateName = `${featureMapEntry.data_stream}@package`; const componentTemplateRes = await esClient.cluster.getComponentTemplate({ name: componentTemplateName }); const componentTemplate = componentTemplateRes.component_templates[0].component_template; const mappings = componentTemplate.template.mappings; const componentTemplateChanged = isDocValueOnlyNumericChanged || isDocValueOnlyOtherChanged || isSyntheticSourceOptInChanged; let mappingsProperties = (_componentTemplate$te = componentTemplate.template.mappings) === null || _componentTemplate$te === void 0 ? void 0 : _componentTemplate$te.properties; if (isDocValueOnlyNumericChanged || isDocValueOnlyOtherChanged) { var _mappings$properties, _properties, _templateMappings$com, _mappings$properties2; (0, _experimental_datastream_features_helper.forEachMappings)((_mappings$properties = mappings === null || mappings === void 0 ? void 0 : mappings.properties) !== null && _mappings$properties !== void 0 ? _mappings$properties : {}, (mappingProp, name) => (0, _experimental_datastream_features_helper.applyDocOnlyValueToMapping)(mappingProp, name, featureMapEntry, isDocValueOnlyNumericChanged, isDocValueOnlyOtherChanged)); const templateProperties = (_properties = ((_templateMappings$com = templateMappings[componentTemplateName]) !== null && _templateMappings$com !== void 0 ? _templateMappings$com : {}).properties) !== null && _properties !== void 0 ? _properties : {}; // merge package spec mappings with generated mappings, so that index:false from package spec is not overwritten mappingsProperties = (0, _lodash.merge)(templateProperties, (_mappings$properties2 = mappings === null || mappings === void 0 ? void 0 : mappings.properties) !== null && _mappings$properties2 !== void 0 ? _mappings$properties2 : {}); } let sourceModeSettings = {}; const indexTemplateRes = await esClient.indices.getIndexTemplate({ name: featureMapEntry.data_stream }); if (isSyntheticSourceOptInChanged) { sourceModeSettings = { _source: { ...(featureMapEntry.features.synthetic_source ? { mode: 'synthetic' } : {}) } }; } if (componentTemplateChanged) { var _mappingsProperties; const body = { template: { ...componentTemplate.template, mappings: { ...mappings, properties: (_mappingsProperties = mappingsProperties) !== null && _mappingsProperties !== void 0 ? _mappingsProperties : {}, ...sourceModeSettings } } }; const hasExperimentalDataStreamIndexingFeatures = featureMapEntry.features.synthetic_source || featureMapEntry.features.doc_value_only_numeric || featureMapEntry.features.doc_value_only_other; await esClient.cluster.putComponentTemplate({ name: componentTemplateName, body, _meta: { has_experimental_data_stream_indexing_features: hasExperimentalDataStreamIndexingFeatures } }); } const indexTemplate = indexTemplateRes.index_templates[0].index_template; let updatedIndexTemplate = indexTemplate; if (isTSDBOptInChanged) { var _indexTemplate$templa, _indexTemplate$templa2, _indexTemplate$templa3; const indexTemplateBody = { ...indexTemplate, template: { ...((_indexTemplate$templa = indexTemplate.template) !== null && _indexTemplate$templa !== void 0 ? _indexTemplate$templa : {}), settings: { ...((_indexTemplate$templa2 = (_indexTemplate$templa3 = indexTemplate.template) === null || _indexTemplate$templa3 === void 0 ? void 0 : _indexTemplate$templa3.settings) !== null && _indexTemplate$templa2 !== void 0 ? _indexTemplate$templa2 : {}), index: { mode: featureMapEntry.features.tsdb ? 'time_series' : null } } } }; updatedIndexTemplate = indexTemplateBody; await esClient.indices.putIndexTemplate({ name: featureMapEntry.data_stream, // @ts-expect-error body: indexTemplateBody, _meta: { has_experimental_data_stream_indexing_features: featureMapEntry.features.tsdb } }); } updatedIndexTemplates.push({ templateName: featureMapEntry.data_stream, indexTemplate: updatedIndexTemplate }); } // Trigger rollover for updated datastreams if (updatedIndexTemplates.length > 0) { await (0, _template.updateCurrentWriteIndices)(esClient, _app_context.appContextService.getLogger(), updatedIndexTemplates); } // Update the installation object to persist the experimental feature map await (0, _update.updateDatastreamExperimentalFeatures)(soClient, packagePolicy.package.name, packagePolicy.package.experimental_data_stream_features); // Delete the experimental features map from the package policy so it doesn't get persisted delete packagePolicy.package.experimental_data_stream_features; }