Check dot-index rules after template application (#52087)

Previously, the dot-index rules (namely, that indices with dot-prefixed
names should be either hidden indices or system indices) was done
before* template application, and so only checked for the `index.hidden`
setting in the request, ignoring if that setting was set via a template.

This commit moves that check to a different method, which is applied
after templates have been resolved and applied to the index settings.
This commit is contained in:
Gordon Brown 2020-02-10 17:01:59 -07:00 committed by GitHub
parent a99b311e2f
commit 350288ddf8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 28 deletions

View File

@ -132,7 +132,7 @@ public class TransportRolloverAction extends TransportMasterNodeAction<RolloverR
final String rolloverIndexName = indexNameExpressionResolver.resolveDateMathExpression(unresolvedName); final String rolloverIndexName = indexNameExpressionResolver.resolveDateMathExpression(unresolvedName);
final Boolean isHidden = IndexMetaData.INDEX_HIDDEN_SETTING.exists(rolloverRequest.getCreateIndexRequest().settings()) ? final Boolean isHidden = IndexMetaData.INDEX_HIDDEN_SETTING.exists(rolloverRequest.getCreateIndexRequest().settings()) ?
IndexMetaData.INDEX_HIDDEN_SETTING.get(rolloverRequest.getCreateIndexRequest().settings()) : null; IndexMetaData.INDEX_HIDDEN_SETTING.get(rolloverRequest.getCreateIndexRequest().settings()) : null;
createIndexService.validateIndexName(rolloverIndexName, state, isHidden); // fails if the index already exists createIndexService.validateIndexName(rolloverIndexName, state); // fails if the index already exists
checkNoDuplicatedAliasInIndexTemplate(metaData, rolloverIndexName, rolloverRequest.getAlias(), isHidden); checkNoDuplicatedAliasInIndexTemplate(metaData, rolloverIndexName, rolloverRequest.getAlias(), isHidden);
IndicesStatsRequest statsRequest = new IndicesStatsRequest().indices(rolloverRequest.getAlias()) IndicesStatsRequest statsRequest = new IndicesStatsRequest().indices(rolloverRequest.getAlias())
.clear() .clear()

View File

@ -169,12 +169,32 @@ public class MetaDataCreateIndexService {
/** /**
* Validate the name for an index against some static rules and a cluster state. * Validate the name for an index against some static rules and a cluster state.
*/ */
public void validateIndexName(String index, ClusterState state, @Nullable Boolean isHidden) { public void validateIndexName(String index, ClusterState state) {
validateIndexOrAliasName(index, InvalidIndexNameException::new); validateIndexOrAliasName(index, InvalidIndexNameException::new);
if (!index.toLowerCase(Locale.ROOT).equals(index)) { if (!index.toLowerCase(Locale.ROOT).equals(index)) {
throw new InvalidIndexNameException(index, "must be lowercase"); throw new InvalidIndexNameException(index, "must be lowercase");
} }
// NOTE: dot-prefixed index names are validated after template application, not here
if (state.routingTable().hasIndex(index)) {
throw new ResourceAlreadyExistsException(state.routingTable().index(index).getIndex());
}
if (state.metaData().hasIndex(index)) {
throw new ResourceAlreadyExistsException(state.metaData().index(index).getIndex());
}
if (state.metaData().hasAlias(index)) {
throw new InvalidIndexNameException(index, "already exists as alias");
}
}
/**
* Validates (if this index has a dot-prefixed name) whether it follows the rules for dot-prefixed indices.
* @param index The name of the index in question
* @param state The current cluster state
* @param isHidden Whether or not this is a hidden index
*/
public void validateDotIndex(String index, ClusterState state, @Nullable Boolean isHidden) {
if (index.charAt(0) == '.') { if (index.charAt(0) == '.') {
List<SystemIndexDescriptor> matchingDescriptors = systemIndexDescriptors.stream() List<SystemIndexDescriptor> matchingDescriptors = systemIndexDescriptors.stream()
.filter(descriptor -> descriptor.matchesIndexPattern(index)) .filter(descriptor -> descriptor.matchesIndexPattern(index))
@ -200,15 +220,6 @@ public class MetaDataCreateIndexService {
throw new IllegalStateException(errorMessage.toString()); throw new IllegalStateException(errorMessage.toString());
} }
} }
if (state.routingTable().hasIndex(index)) {
throw new ResourceAlreadyExistsException(state.routingTable().index(index).getIndex());
}
if (state.metaData().hasIndex(index)) {
throw new ResourceAlreadyExistsException(state.metaData().index(index).getIndex());
}
if (state.metaData().hasAlias(index)) {
throw new InvalidIndexNameException(index, "already exists as alias");
}
} }
/** /**
@ -322,10 +333,12 @@ public class MetaDataCreateIndexService {
// we only find a template when its an API call (a new index) // we only find a template when its an API call (a new index)
// find templates, highest order are better matching // find templates, highest order are better matching
final Boolean isHidden = IndexMetaData.INDEX_HIDDEN_SETTING.exists(request.settings()) ? final Boolean isHiddenFromRequest = IndexMetaData.INDEX_HIDDEN_SETTING.exists(request.settings()) ?
IndexMetaData.INDEX_HIDDEN_SETTING.get(request.settings()) : null; IndexMetaData.INDEX_HIDDEN_SETTING.get(request.settings()) : null;
final List<IndexTemplateMetaData> templates = sourceMetaData == null ? final List<IndexTemplateMetaData> templates = sourceMetaData == null ?
Collections.unmodifiableList(MetaDataIndexTemplateService.findTemplates(currentState.metaData(), request.index(), isHidden)) : Collections.unmodifiableList(MetaDataIndexTemplateService.findTemplates(currentState.metaData(),
request.index(),
isHiddenFromRequest)) :
Collections.emptyList(); Collections.emptyList();
final Map<String, Map<String, Object>> mappings = Collections.unmodifiableMap(parseMappings(request.mappings(), templates, final Map<String, Map<String, Object>> mappings = Collections.unmodifiableMap(parseMappings(request.mappings(), templates,
@ -335,6 +348,9 @@ public class MetaDataCreateIndexService {
aggregateIndexSettings(currentState, request, templates, mappings, sourceMetaData, settings, indexScopedSettings); aggregateIndexSettings(currentState, request, templates, mappings, sourceMetaData, settings, indexScopedSettings);
int routingNumShards = getIndexNumberOfRoutingShards(aggregatedIndexSettings, sourceMetaData); int routingNumShards = getIndexNumberOfRoutingShards(aggregatedIndexSettings, sourceMetaData);
final boolean isHiddenAfterTemplates = IndexMetaData.INDEX_HIDDEN_SETTING.get(aggregatedIndexSettings);
validateDotIndex(request.index(), currentState, isHiddenAfterTemplates);
// remove the setting it's temporary and is only relevant once we create the index // remove the setting it's temporary and is only relevant once we create the index
final Settings.Builder settingsBuilder = Settings.builder().put(aggregatedIndexSettings); final Settings.Builder settingsBuilder = Settings.builder().put(aggregatedIndexSettings);
settingsBuilder.remove(IndexMetaData.INDEX_NUMBER_OF_ROUTING_SHARDS_SETTING.getKey()); settingsBuilder.remove(IndexMetaData.INDEX_NUMBER_OF_ROUTING_SHARDS_SETTING.getKey());
@ -742,8 +758,7 @@ public class MetaDataCreateIndexService {
} }
private void validate(CreateIndexClusterStateUpdateRequest request, ClusterState state) { private void validate(CreateIndexClusterStateUpdateRequest request, ClusterState state) {
boolean isHidden = IndexMetaData.INDEX_HIDDEN_SETTING.get(request.settings()); validateIndexName(request.index(), state);
validateIndexName(request.index(), state, isHidden);
validateIndexSettings(request.index(), request.settings(), forbidPrivateIndexSettings); validateIndexSettings(request.index(), request.settings(), forbidPrivateIndexSettings);
} }

View File

@ -279,7 +279,8 @@ public class RestoreService implements ClusterStateApplier {
// Index doesn't exist - create it and start recovery // Index doesn't exist - create it and start recovery
// Make sure that the index we are about to create has a validate name // Make sure that the index we are about to create has a validate name
boolean isHidden = IndexMetaData.INDEX_HIDDEN_SETTING.get(snapshotIndexMetaData.getSettings()); boolean isHidden = IndexMetaData.INDEX_HIDDEN_SETTING.get(snapshotIndexMetaData.getSettings());
createIndexService.validateIndexName(renamedIndexName, currentState, isHidden); createIndexService.validateIndexName(renamedIndexName, currentState);
createIndexService.validateDotIndex(renamedIndexName, currentState, isHidden);
createIndexService.validateIndexSettings(renamedIndexName, snapshotIndexMetaData.getSettings(), false); createIndexService.validateIndexSettings(renamedIndexName, snapshotIndexMetaData.getSettings(), false);
IndexMetaData.Builder indexMdBuilder = IndexMetaData.builder(snapshotIndexMetaData) IndexMetaData.Builder indexMdBuilder = IndexMetaData.builder(snapshotIndexMetaData)
.state(IndexMetaData.State.OPEN) .state(IndexMetaData.State.OPEN)

View File

@ -517,7 +517,7 @@ public class MetaDataCreateIndexServiceTests extends ESTestCase {
private void validateIndexName(MetaDataCreateIndexService metaDataCreateIndexService, String indexName, String errorMessage) { private void validateIndexName(MetaDataCreateIndexService metaDataCreateIndexService, String indexName, String errorMessage) {
InvalidIndexNameException e = expectThrows(InvalidIndexNameException.class, InvalidIndexNameException e = expectThrows(InvalidIndexNameException.class,
() -> metaDataCreateIndexService.validateIndexName(indexName, ClusterState.builder(ClusterName.CLUSTER_NAME_SETTING () -> metaDataCreateIndexService.validateIndexName(indexName, ClusterState.builder(ClusterName.CLUSTER_NAME_SETTING
.getDefault(Settings.EMPTY)).build(), false)); .getDefault(Settings.EMPTY)).build()));
assertThat(e.getMessage(), endsWith(errorMessage)); assertThat(e.getMessage(), endsWith(errorMessage));
} }
@ -586,7 +586,7 @@ public class MetaDataCreateIndexServiceTests extends ESTestCase {
assertThat(e, hasToString(containsString(expectedMessage))); assertThat(e, hasToString(containsString(expectedMessage)));
} }
public void testValidateIndexNameChecksSystemIndexNames() { public void testValidateDotIndex() {
List<SystemIndexDescriptor> systemIndexDescriptors = new ArrayList<>(); List<SystemIndexDescriptor> systemIndexDescriptors = new ArrayList<>();
systemIndexDescriptors.add(new SystemIndexDescriptor(".test", "test")); systemIndexDescriptors.add(new SystemIndexDescriptor(".test", "test"));
systemIndexDescriptors.add(new SystemIndexDescriptor(".test3", "test")); systemIndexDescriptors.add(new SystemIndexDescriptor(".test3", "test"));
@ -609,25 +609,25 @@ public class MetaDataCreateIndexServiceTests extends ESTestCase {
false false
); );
// Check deprecations // Check deprecations
checkerService.validateIndexName(".test2", ClusterState.EMPTY_STATE, false); checkerService.validateDotIndex(".test2", ClusterState.EMPTY_STATE, false);
assertWarnings("index name [.test2] starts with a dot '.', in the next major version, index " + assertWarnings("index name [.test2] starts with a dot '.', in the next major version, index " +
"names starting with a dot are reserved for hidden indices and system indices"); "names starting with a dot are reserved for hidden indices and system indices");
// Check non-system hidden indices don't trigger a warning // Check non-system hidden indices don't trigger a warning
checkerService.validateIndexName(".test2", ClusterState.EMPTY_STATE, true); checkerService.validateDotIndex(".test2", ClusterState.EMPTY_STATE, true);
// Check NO deprecation warnings if we give the index name // Check NO deprecation warnings if we give the index name
checkerService.validateIndexName(".test", ClusterState.EMPTY_STATE, false); checkerService.validateDotIndex(".test", ClusterState.EMPTY_STATE, false);
checkerService.validateIndexName(".test3", ClusterState.EMPTY_STATE, false); checkerService.validateDotIndex(".test3", ClusterState.EMPTY_STATE, false);
// Check that patterns with wildcards work // Check that patterns with wildcards work
checkerService.validateIndexName(".pattern-test", ClusterState.EMPTY_STATE, false); checkerService.validateDotIndex(".pattern-test", ClusterState.EMPTY_STATE, false);
checkerService.validateIndexName(".pattern-test-with-suffix", ClusterState.EMPTY_STATE, false); checkerService.validateDotIndex(".pattern-test-with-suffix", ClusterState.EMPTY_STATE, false);
checkerService.validateIndexName(".pattern-test-other-suffix", ClusterState.EMPTY_STATE, false); checkerService.validateDotIndex(".pattern-test-other-suffix", ClusterState.EMPTY_STATE, false);
// Check that an exception is thrown if more than one descriptor matches the index name // Check that an exception is thrown if more than one descriptor matches the index name
AssertionError exception = expectThrows(AssertionError.class, AssertionError exception = expectThrows(AssertionError.class,
() -> checkerService.validateIndexName(".pattern-test-overlapping", ClusterState.EMPTY_STATE, false)); () -> checkerService.validateDotIndex(".pattern-test-overlapping", ClusterState.EMPTY_STATE, false));
assertThat(exception.getMessage(), assertThat(exception.getMessage(),
containsString("index name [.pattern-test-overlapping] is claimed as a system index by multiple system index patterns:")); containsString("index name [.pattern-test-overlapping] is claimed as a system index by multiple system index patterns:"));
assertThat(exception.getMessage(), containsString("pattern: [.pattern-test*], description: [test-1]")); assertThat(exception.getMessage(), containsString("pattern: [.pattern-test*], description: [test-1]"));
@ -667,11 +667,11 @@ public class MetaDataCreateIndexServiceTests extends ESTestCase {
); );
excludedNames.forEach(name -> { excludedNames.forEach(name -> {
checkerService.validateIndexName(name, ClusterState.EMPTY_STATE, false); checkerService.validateDotIndex(name, ClusterState.EMPTY_STATE, false);
}); });
excludedNames.forEach(name -> { excludedNames.forEach(name -> {
expectThrows(AssertionError.class, () -> checkerService.validateIndexName(name, ClusterState.EMPTY_STATE, true)); expectThrows(AssertionError.class, () -> checkerService.validateDotIndex(name, ClusterState.EMPTY_STATE, true));
}); });
} finally { } finally {
testThreadPool.shutdown(); testThreadPool.shutdown();