/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.elasticsearch.action.support; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.common.Booleans; import org.elasticsearch.common.Strings; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.mapper.MapperService; import java.util.ArrayList; import java.util.List; /** * Encapsulates the logic of whether a new index should be automatically created when * a write operation is about to happen in a non existing index. */ public final class AutoCreateIndex { public static final Setting<AutoCreate> AUTO_CREATE_INDEX_SETTING = new Setting<>("action.auto_create_index", "true", AutoCreate::new, Property.NodeScope, Setting.Property.Dynamic); private final boolean dynamicMappingDisabled; private final IndexNameExpressionResolver resolver; private volatile AutoCreate autoCreate; public AutoCreateIndex(Settings settings, ClusterSettings clusterSettings, IndexNameExpressionResolver resolver) { this.resolver = resolver; dynamicMappingDisabled = !MapperService.INDEX_MAPPER_DYNAMIC_SETTING.get(settings); this.autoCreate = AUTO_CREATE_INDEX_SETTING.get(settings); clusterSettings.addSettingsUpdateConsumer(AUTO_CREATE_INDEX_SETTING, this::setAutoCreate); } /** * Do we really need to check if an index should be auto created? */ public boolean needToCheck() { return this.autoCreate.autoCreateIndex; } /** * Should the index be auto created? * @throws IndexNotFoundException if the the index doesn't exist and shouldn't be auto created */ public boolean shouldAutoCreate(String index, ClusterState state) { if (resolver.hasIndexOrAlias(index, state)) { return false; } // One volatile read, so that all checks are done against the same instance: final AutoCreate autoCreate = this.autoCreate; if (autoCreate.autoCreateIndex == false) { throw new IndexNotFoundException("no such index and [" + AUTO_CREATE_INDEX_SETTING.getKey() + "] is [false]", index); } if (dynamicMappingDisabled) { throw new IndexNotFoundException("no such index and [" + MapperService.INDEX_MAPPER_DYNAMIC_SETTING.getKey() + "] is [false]", index); } // matches not set, default value of "true" if (autoCreate.expressions.isEmpty()) { return true; } for (Tuple<String, Boolean> expression : autoCreate.expressions) { String indexExpression = expression.v1(); boolean include = expression.v2(); if (Regex.simpleMatch(indexExpression, index)) { if (include) { return true; } throw new IndexNotFoundException("no such index and [" + AUTO_CREATE_INDEX_SETTING.getKey() + "] contains [-" + indexExpression + "] which forbids automatic creation of the index", index); } } throw new IndexNotFoundException("no such index and [" + AUTO_CREATE_INDEX_SETTING.getKey() + "] ([" + autoCreate + "]) doesn't match", index); } AutoCreate getAutoCreate() { return autoCreate; } void setAutoCreate(AutoCreate autoCreate) { this.autoCreate = autoCreate; } static class AutoCreate { private final boolean autoCreateIndex; private final List<Tuple<String, Boolean>> expressions; private final String string; private AutoCreate(String value) { boolean autoCreateIndex; List<Tuple<String, Boolean>> expressions = new ArrayList<>(); try { autoCreateIndex = Booleans.parseBoolean(value); } catch (IllegalArgumentException ex) { try { String[] patterns = Strings.commaDelimitedListToStringArray(value); for (String pattern : patterns) { if (pattern == null || pattern.trim().length() == 0) { throw new IllegalArgumentException("Can't parse [" + value + "] for setting [action.auto_create_index] must " + "be either [true, false, or a comma separated list of index patterns]"); } pattern = pattern.trim(); Tuple<String, Boolean> expression; if (pattern.startsWith("-")) { if (pattern.length() == 1) { throw new IllegalArgumentException("Can't parse [" + value + "] for setting [action.auto_create_index] " + "must contain an index name after [-]"); } expression = new Tuple<>(pattern.substring(1), false); } else if(pattern.startsWith("+")) { if (pattern.length() == 1) { throw new IllegalArgumentException("Can't parse [" + value + "] for setting [action.auto_create_index] " + "must contain an index name after [+]"); } expression = new Tuple<>(pattern.substring(1), true); } else { expression = new Tuple<>(pattern, true); } expressions.add(expression); } autoCreateIndex = true; } catch (IllegalArgumentException ex1) { ex1.addSuppressed(ex); throw ex1; } } this.expressions = expressions; this.autoCreateIndex = autoCreateIndex; this.string = value; } boolean isAutoCreateIndex() { return autoCreateIndex; } List<Tuple<String, Boolean>> getExpressions() { return expressions; } @Override public String toString() { return string; } } }