/* Copyright OpenSearch Contributors SPDX-License-Identifier: Apache-2.0 */ package org.opensearch.securityanalytics.mapper; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.opensearch.cluster.ClusterState; import org.opensearch.cluster.metadata.ComposableIndexTemplate; import org.opensearch.cluster.metadata.Template; import org.opensearch.common.bytes.BytesReference; import org.opensearch.common.compress.CompressedXContent; import org.opensearch.common.xcontent.XContentFactory; import org.opensearch.common.xcontent.XContentHelper; import org.opensearch.common.xcontent.XContentType; import org.opensearch.core.xcontent.XContentBuilder; import static org.opensearch.index.mapper.MapperService.SINGLE_MAPPING_NAME; import static org.opensearch.securityanalytics.mapper.IndexTemplateManager.OPENSEARCH_SAP_COMPONENT_TEMPLATE_PREFIX; import static org.opensearch.securityanalytics.mapper.IndexTemplateManager.OPENSEARCH_SAP_INDEX_TEMPLATE_PREFIX; public class IndexTemplateUtils { public static Set<String> getAllSapComponentTemplates(ClusterState state) { Set<String> componentTemplates = new HashSet<>(); state.metadata().componentTemplates().forEach( (name, instance) -> { if (name.startsWith(OPENSEARCH_SAP_COMPONENT_TEMPLATE_PREFIX)) { componentTemplates.add(name); } }); return componentTemplates; } public static boolean isSapComposableIndexTemplate(String templateName, ComposableIndexTemplate template) { // We don't ever set template field inside ComposableIndexTemplate and our template always starts with OPENSEARCH_SAP_INDEX_TEMPLATE_PREFIX // If any of these is true, that means that user touched template and we're not owner of it anymore if (templateName.startsWith(OPENSEARCH_SAP_INDEX_TEMPLATE_PREFIX) == false || template.template() != null) { return false; } // If user added ComponentTemplate then this ComposableIndexTemplate is owned by user for (String componentTemplate : template.composedOf()) { if (componentTemplate.startsWith(OPENSEARCH_SAP_COMPONENT_TEMPLATE_PREFIX) == false) { return false; } } return true; } public static Map<String, ComposableIndexTemplate> getAllSapComposableIndexTemplates(ClusterState state) { Map<String, ComposableIndexTemplate> sapTemplates = new HashMap<>(); state.metadata().templatesV2().forEach( (name, instance) -> { if (isSapComposableIndexTemplate(name, instance)) { sapTemplates.put(name, instance); } }); return sapTemplates; } public static String computeIndexTemplateName(String indexName) { return OPENSEARCH_SAP_INDEX_TEMPLATE_PREFIX + normalizeIndexName(indexName); } public static String computeComponentTemplateName(String indexName) { if (indexName.endsWith("*")) { indexName = indexName.substring(0, indexName.length() - 1); } return OPENSEARCH_SAP_COMPONENT_TEMPLATE_PREFIX + normalizeIndexName(indexName); } public static String normalizeIndexName(String indexName) { if (indexName.endsWith("*")) { return indexName.substring(0, indexName.length() - 1); } else { return indexName; } } public static boolean isUserCreatedComposableTemplate(String templateName) { return templateName.startsWith(OPENSEARCH_SAP_INDEX_TEMPLATE_PREFIX) == false; } public static Template copyTemplate(Template template) throws IOException { if (template == null) { return null; } CompressedXContent outMappings = null; CompressedXContent mappings = template.mappings(); if (mappings != null) { Map<String, Object> mappingsAsMap = XContentHelper.convertToMap(mappings.compressedReference(), true, XContentType.JSON).v2(); if (mappingsAsMap.containsKey(SINGLE_MAPPING_NAME)) { mappingsAsMap = (Map<String, Object>)mappingsAsMap.get(SINGLE_MAPPING_NAME); } XContentBuilder builder = XContentFactory.jsonBuilder(); builder.map(mappingsAsMap); outMappings = new CompressedXContent(BytesReference.bytes(builder)); } return new Template( template.settings(), outMappings, template.aliases() ); } }