|
9 | 9 | import org.apache.logging.log4j.LogManager; |
10 | 10 | import org.apache.logging.log4j.Logger; |
11 | 11 | import org.elasticsearch.ElasticsearchException; |
| 12 | +import org.elasticsearch.ResourceNotFoundException; |
12 | 13 | import org.elasticsearch.action.ActionListener; |
13 | 14 | import org.elasticsearch.action.ActionRequest; |
14 | 15 | import org.elasticsearch.action.ActionResponse; |
|
43 | 44 | import org.elasticsearch.common.settings.Settings; |
44 | 45 | import org.elasticsearch.common.util.Maps; |
45 | 46 | import org.elasticsearch.common.util.iterable.Iterables; |
| 47 | +import org.elasticsearch.index.IndexNotFoundException; |
46 | 48 | import org.elasticsearch.index.IndexVersion; |
47 | 49 | import org.elasticsearch.index.mapper.Mapper; |
48 | 50 | import org.elasticsearch.index.mapper.MapperService; |
@@ -132,13 +134,9 @@ public void run() { |
132 | 134 | logger.debug("Policy [{}]: Checking source indices [{}]", policyName, sourceIndices); |
133 | 135 | GetIndexRequest getIndexRequest = new GetIndexRequest().indices(sourceIndices); |
134 | 136 | // This call does not set the origin to ensure that the user executing the policy has permission to access the source index |
135 | | - client.admin().indices().getIndex(getIndexRequest, listener.delegateFailure((l, getIndexResponse) -> { |
136 | | - try { |
137 | | - validateMappings(getIndexResponse); |
138 | | - prepareAndCreateEnrichIndex(toMappings(getIndexResponse)); |
139 | | - } catch (Exception e) { |
140 | | - l.onFailure(e); |
141 | | - } |
| 137 | + client.admin().indices().getIndex(getIndexRequest, listener.delegateFailureAndWrap((l, getIndexResponse) -> { |
| 138 | + validateMappings(getIndexResponse); |
| 139 | + prepareAndCreateEnrichIndex(toMappings(getIndexResponse)); |
142 | 140 | })); |
143 | 141 | } catch (Exception e) { |
144 | 142 | listener.onFailure(e); |
@@ -624,14 +622,66 @@ private void waitForIndexGreen(final String destinationIndexName) { |
624 | 622 | ClusterHealthRequest request = new ClusterHealthRequest(destinationIndexName).waitForGreenStatus(); |
625 | 623 | enrichOriginClient().admin() |
626 | 624 | .cluster() |
627 | | - .health(request, listener.delegateFailure((l, r) -> updateEnrichPolicyAlias(destinationIndexName))); |
| 625 | + .health(request, listener.delegateFailureAndWrap((l, r) -> updateEnrichPolicyAlias(destinationIndexName))); |
| 626 | + } |
| 627 | + |
| 628 | + /** |
| 629 | + * Ensures that the index we are about to promote at the end of a policy execution exists, is intact, and has not been damaged |
| 630 | + * during the policy execution. In some cases, it is possible for the index being constructed to be deleted during the policy execution |
| 631 | + * and recreated with invalid mappings/data. We validate that the mapping exists and that it contains the expected meta fields on it to |
| 632 | + * guard against accidental removal and recreation during policy execution. |
| 633 | + */ |
| 634 | + private void validateIndexBeforePromotion(String destinationIndexName, ClusterState clusterState) { |
| 635 | + IndexMetadata destinationIndex = clusterState.metadata().index(destinationIndexName); |
| 636 | + if (destinationIndex == null) { |
| 637 | + throw new IndexNotFoundException( |
| 638 | + "was not able to promote it as part of executing enrich policy [" + policyName + "]", |
| 639 | + destinationIndexName |
| 640 | + ); |
| 641 | + } |
| 642 | + MappingMetadata mapping = destinationIndex.mapping(); |
| 643 | + if (mapping == null) { |
| 644 | + throw new ResourceNotFoundException( |
| 645 | + "Could not locate mapping for enrich index [{}] while completing [{}] policy run", |
| 646 | + destinationIndexName, |
| 647 | + policyName |
| 648 | + ); |
| 649 | + } |
| 650 | + Map<String, Object> mappingSource = mapping.sourceAsMap(); |
| 651 | + Object meta = mappingSource.get("_meta"); |
| 652 | + if (meta instanceof Map<?, ?> metaMap) { |
| 653 | + Object policyNameMetaField = metaMap.get(ENRICH_POLICY_NAME_FIELD_NAME); |
| 654 | + if (policyNameMetaField == null) { |
| 655 | + throw new ElasticsearchException( |
| 656 | + "Could not verify enrich index [{}] metadata before completing [{}] policy run: policy name meta field missing", |
| 657 | + destinationIndexName, |
| 658 | + policyName |
| 659 | + ); |
| 660 | + } else if (policyName.equals(policyNameMetaField) == false) { |
| 661 | + throw new ElasticsearchException( |
| 662 | + "Could not verify enrich index [{}] metadata before completing [{}] policy run: policy name meta field does not " |
| 663 | + + "match expected value of [{}], was [{}]", |
| 664 | + destinationIndexName, |
| 665 | + policyName, |
| 666 | + policyName, |
| 667 | + policyNameMetaField.toString() |
| 668 | + ); |
| 669 | + } |
| 670 | + } else { |
| 671 | + throw new ElasticsearchException( |
| 672 | + "Could not verify enrich index [{}] metadata before completing [{}] policy run: mapping meta field missing", |
| 673 | + destinationIndexName, |
| 674 | + policyName |
| 675 | + ); |
| 676 | + } |
628 | 677 | } |
629 | 678 |
|
630 | 679 | private void updateEnrichPolicyAlias(final String destinationIndexName) { |
631 | 680 | String enrichIndexBase = EnrichPolicy.getBaseName(policyName); |
632 | 681 | logger.debug("Policy [{}]: Promoting new enrich index [{}] to alias [{}]", policyName, destinationIndexName, enrichIndexBase); |
633 | 682 | GetAliasesRequest aliasRequest = new GetAliasesRequest(enrichIndexBase); |
634 | 683 | ClusterState clusterState = clusterService.state(); |
| 684 | + validateIndexBeforePromotion(destinationIndexName, clusterState); |
635 | 685 | String[] concreteIndices = indexNameExpressionResolver.concreteIndexNamesWithSystemIndexAccess(clusterState, aliasRequest); |
636 | 686 | String[] aliases = aliasRequest.aliases(); |
637 | 687 | IndicesAliasesRequest aliasToggleRequest = new IndicesAliasesRequest(); |
|
0 commit comments