Browse Source

Fix remove alias with must_exist (#65141)

Remove alias now parses the must_exist flag and results in a 404
(not found), if the index does not have the alias.

Closes #62642
Relates #58100

Co-Authored-By: Luca Cavanna <javanna@users.noreply.github.com>
Henning Andersen 4 years ago
parent
commit
67e1128e05

+ 84 - 0
rest-api-spec/src/main/resources/rest-api-spec/test/indices.update_aliases/40_must_exist.yml

@@ -0,0 +1,84 @@
+---
+"Remove alias with must_exist":
+
+  - skip:
+      version: " - 7.99.99" # TODO: 7.10.99
+      reason: "must_exist does not work until 7.11"
+
+  - do:
+      indices.create:
+        index: test_index
+
+  - do:
+      indices.update_aliases:
+        body:
+          actions:
+            - add:
+                index: test_index
+                aliases: test_alias1
+  - do:
+      indices.exists_alias:
+        name: test_alias1
+  - is_true: ''
+
+  - do:
+      indices.update_aliases:
+        body:
+          actions:
+            - remove:
+                index: test_index
+                alias: test_alias1
+                must_exist: true
+            - add:
+                index: test_index
+                alias: test_alias2
+  - do:
+      indices.exists_alias:
+        name: test_alias1
+  - is_false: ''
+  - do:
+      indices.exists_alias:
+        name: test_alias2
+  - is_true: ''
+
+  - do:
+      catch: missing
+      indices.update_aliases:
+        body:
+          actions:
+            - remove:
+                index: test_index
+                alias: test_alias1
+                must_exist: true
+            - add:
+                index: test_index
+                alias: test_alias3
+  - do:
+      indices.exists_alias:
+        name: test_alias3
+  - is_false: ''
+
+---
+"Alias must_exist only on remove":
+  - do:
+      indices.create:
+        index: test_index
+
+  - do:
+      catch: bad_request
+      indices.update_aliases:
+        body:
+          actions:
+            - add:
+                index: test_index
+                aliases: test_alias1
+                must_exist: true
+
+  - do:
+      catch: bad_request
+      indices.update_aliases:
+        body:
+          actions:
+            - remove_index:
+                index: test_index
+                must_exist: true

+ 11 - 6
server/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequest.java

@@ -177,6 +177,9 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
         }
 
         private static final ObjectParser<AliasActions, Void> ADD_PARSER = parser(ADD.getPreferredName(), AliasActions::add);
+        private static final ObjectParser<AliasActions, Void> REMOVE_PARSER = parser(REMOVE.getPreferredName(), AliasActions::remove);
+        private static final ObjectParser<AliasActions, Void> REMOVE_INDEX_PARSER = parser(REMOVE_INDEX.getPreferredName(),
+            AliasActions::removeIndex);
         static {
             ADD_PARSER.declareObject(AliasActions::filter, (parser, m) -> {
                 try {
@@ -191,11 +194,8 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
             ADD_PARSER.declareField(AliasActions::searchRouting, XContentParser::text, SEARCH_ROUTING, ValueType.INT);
             ADD_PARSER.declareField(AliasActions::writeIndex, XContentParser::booleanValue, IS_WRITE_INDEX, ValueType.BOOLEAN);
             ADD_PARSER.declareField(AliasActions::isHidden, XContentParser::booleanValue, IS_HIDDEN, ValueType.BOOLEAN);
-            ADD_PARSER.declareField(AliasActions::mustExist, XContentParser::booleanValue, MUST_EXIST, ValueType.BOOLEAN);
+            REMOVE_PARSER.declareField(AliasActions::mustExist, XContentParser::booleanValue, MUST_EXIST, ValueType.BOOLEAN);
         }
-        private static final ObjectParser<AliasActions, Void> REMOVE_PARSER = parser(REMOVE.getPreferredName(), AliasActions::remove);
-        private static final ObjectParser<AliasActions, Void> REMOVE_INDEX_PARSER = parser(REMOVE_INDEX.getPreferredName(),
-                AliasActions::removeIndex);
 
         /**
          * Parser for any one {@link AliasAction}.
@@ -524,6 +524,9 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
             if (null != isHidden) {
                 builder.field(IS_HIDDEN.getPreferredName(), isHidden);
             }
+            if (null != mustExist) {
+                builder.field(MUST_EXIST.getPreferredName(), mustExist);
+            }
             builder.endObject();
             builder.endObject();
             return builder;
@@ -544,6 +547,7 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
                     + ",indexRouting=" + indexRouting
                     + ",searchRouting=" + searchRouting
                     + ",writeIndex=" + writeIndex
+                    + ",mustExist=" + mustExist
                     + "]";
         }
 
@@ -562,12 +566,13 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
                     && Objects.equals(indexRouting, other.indexRouting)
                     && Objects.equals(searchRouting, other.searchRouting)
                     && Objects.equals(writeIndex, other.writeIndex)
-                    && Objects.equals(isHidden, other.isHidden);
+                    && Objects.equals(isHidden, other.isHidden)
+                    && Objects.equals(mustExist, other.mustExist);
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(type, indices, aliases, filter, routing, indexRouting, searchRouting, writeIndex, isHidden);
+            return Objects.hash(type, indices, aliases, filter, routing, indexRouting, searchRouting, writeIndex, isHidden, mustExist);
         }
     }
 

+ 3 - 0
server/src/main/java/org/elasticsearch/action/admin/indices/alias/TransportIndicesAliasesAction.java

@@ -171,6 +171,9 @@ public class TransportIndicesAliasesAction extends AcknowledgedTransportMasterNo
                     finalAliases.add(aliasMeta.alias());
                 }
             }
+            if (finalAliases.isEmpty() && action.mustExist() != null && action.mustExist()) {
+                return action.aliases();
+            }
             return finalAliases.toArray(new String[finalAliases.size()]);
         } else {
             //for ADD and REMOVE_INDEX we just return the current aliases

+ 3 - 2
server/src/main/java/org/elasticsearch/cluster/metadata/AliasAction.java

@@ -19,6 +19,7 @@
 
 package org.elasticsearch.cluster.metadata;
 
+import org.elasticsearch.ResourceNotFoundException;
 import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
 import org.elasticsearch.common.Nullable;
 import org.elasticsearch.common.Strings;
@@ -179,8 +180,8 @@ public abstract class AliasAction {
         @Override
         boolean apply(NewAliasValidator aliasValidator, Metadata.Builder metadata, IndexMetadata index) {
             if (false == index.getAliases().containsKey(alias)) {
-                if (mustExist != null && mustExist.booleanValue()) {
-                    throw new IllegalArgumentException("required alias [" + alias  + "] does not exist");
+                if (mustExist != null && mustExist) {
+                    throw new ResourceNotFoundException("required alias [" + alias  + "] does not exist");
                 }
                 return false;
             }

+ 6 - 0
server/src/test/java/org/elasticsearch/action/admin/indices/alias/AliasActionsTests.java

@@ -216,6 +216,7 @@ public class AliasActionsTests extends ESTestCase {
     public void testParseRemove() throws IOException {
         String[] indices = generateRandomStringArray(10, 5, false, false);
         String[] aliases = generateRandomStringArray(10, 5, false, false);
+        Boolean mustExist = null;
         XContentBuilder b = XContentBuilder.builder(randomFrom(XContentType.values()).xContent());
         b.startObject();
         {
@@ -231,6 +232,10 @@ public class AliasActionsTests extends ESTestCase {
                 } else {
                     b.field("alias", aliases[0]);
                 }
+                if (randomBoolean()) {
+                    mustExist = randomBoolean();
+                    b.field("must_exist", mustExist);
+                }
             }
             b.endObject();
         }
@@ -241,6 +246,7 @@ public class AliasActionsTests extends ESTestCase {
             assertEquals(AliasActions.Type.REMOVE, action.actionType());
             assertThat(action.indices(), equalTo(indices));
             assertThat(action.aliases(), equalTo(aliases));
+            assertThat(action.mustExist(), equalTo(mustExist));
         }
     }
 

+ 2 - 1
server/src/test/java/org/elasticsearch/cluster/metadata/MetadataIndexAliasesServiceTests.java

@@ -19,6 +19,7 @@
 
 package org.elasticsearch.cluster.metadata;
 
+import org.elasticsearch.ResourceNotFoundException;
 import org.elasticsearch.Version;
 import org.elasticsearch.cluster.ClusterName;
 import org.elasticsearch.cluster.ClusterState;
@@ -138,7 +139,7 @@ public class MetadataIndexAliasesServiceTests extends ESTestCase {
 
         // Show that removing non-existing alias with mustExist == true fails
         final ClusterState finalCS = after;
-        final IllegalArgumentException iae = expectThrows(IllegalArgumentException.class,
+        final ResourceNotFoundException iae = expectThrows(ResourceNotFoundException.class,
             () -> service.applyAliasActions(finalCS, singletonList(new AliasAction.Remove(index, "test_2", true))));
         assertThat(iae.getMessage(), containsString("required alias [test_2] does not exist"));
     }

+ 5 - 0
test/framework/src/main/java/org/elasticsearch/index/alias/RandomAliasActionsGenerator.java

@@ -54,6 +54,11 @@ public final class RandomAliasActionsGenerator {
             }
             action.indices(indices);
         }
+        if (action.actionType() == AliasActions.Type.REMOVE) {
+            if (randomBoolean()) {
+                action.mustExist(randomBoolean());
+            }
+        }
         if (action.actionType() != AliasActions.Type.REMOVE_INDEX) {
             if (randomBoolean()) {
                 action.alias(randomAlphaOfLength(5));