You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by ge...@apache.org on 2023/03/15 14:22:38 UTC

[solr] branch main updated: SOLR-16393: Migrate alias-deletion to JAX-RS (#1452)

This is an automated email from the ASF dual-hosted git repository.

gerlowskija pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new 52504fa27dd SOLR-16393: Migrate alias-deletion to JAX-RS (#1452)
52504fa27dd is described below

commit 52504fa27dd5f603e74b10e84e0ff830c55c9fc3
Author: Jason Gerlowski <ge...@apache.org>
AuthorDate: Wed Mar 15 10:22:29 2023 -0400

    SOLR-16393: Migrate alias-deletion to JAX-RS (#1452)
    
    This commit makes various cosmetic improvements to Solr's v2 delete
    alias API, to bring it more into line with the more REST-ful v2
    design.  In the process it also converts the API to the JAX-RS
    framework.
    
    As of this commit, the delete-alias API is now
        - DELETE /api/aliases/aliasName
---
 solr/CHANGES.txt                                   |  6 ++
 .../org/apache/solr/handler/CollectionsAPI.java    | 12 ---
 .../solr/handler/admin/CollectionsHandler.java     | 13 ++-
 .../solr/handler/admin/api/DeleteAliasAPI.java     | 92 ++++++++++++++++++++++
 .../apache/solr/jersey/AsyncJerseyResponse.java}   | 12 ++-
 .../SubResponseAccumulatingJerseyResponse.java     |  5 +-
 .../solr/handler/admin/TestCollectionAPIs.java     |  7 --
 .../handler/admin/V2CollectionsAPIMappingTest.java | 13 ---
 .../solr/handler/admin/api/DeleteAliasAPITest.java | 45 +++++++++++
 .../deployment-guide/pages/alias-management.adoc   | 10 +--
 10 files changed, 163 insertions(+), 52 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index c33f66c9a77..202d941b40c 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -45,6 +45,12 @@ Improvements
 Bug Fixes
 ---------------------
 
+Improvements
+---------------------
+
+* SOLR-16393: The path of the v2 "delete alias" API has been tweaked slightly to be more intuitive, and is now available at
+  `DELETE /api/aliases/aliasName`. (Jason Gerlowski)
+
 ==================  9.2.0 ==================
 
 New Features
diff --git a/solr/core/src/java/org/apache/solr/handler/CollectionsAPI.java b/solr/core/src/java/org/apache/solr/handler/CollectionsAPI.java
index a2b76ced5b8..1e3aeac45ee 100644
--- a/solr/core/src/java/org/apache/solr/handler/CollectionsAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/CollectionsAPI.java
@@ -39,7 +39,6 @@ import org.apache.solr.api.PayloadObj;
 import org.apache.solr.client.solrj.request.beans.BackupCollectionPayload;
 import org.apache.solr.client.solrj.request.beans.CreateAliasPayload;
 import org.apache.solr.client.solrj.request.beans.CreatePayload;
-import org.apache.solr.client.solrj.request.beans.DeleteAliasPayload;
 import org.apache.solr.client.solrj.request.beans.RestoreCollectionPayload;
 import org.apache.solr.client.solrj.request.beans.SetAliasPropertyPayload;
 import org.apache.solr.client.solrj.request.beans.V2ApiConstants;
@@ -55,7 +54,6 @@ public class CollectionsAPI {
   public static final String V2_RESTORE_CMD = "restore-collection";
   public static final String V2_CREATE_ALIAS_CMD = "create-alias";
   public static final String V2_SET_ALIAS_PROP_CMD = "set-alias-property";
-  public static final String V2_DELETE_ALIAS_CMD = "delete-alias";
 
   private final CollectionsHandler collectionsHandler;
 
@@ -142,16 +140,6 @@ public class CollectionsAPI {
           wrapParams(obj.getRequest(), v1Params), obj.getResponse());
     }
 
-    @Command(name = V2_DELETE_ALIAS_CMD)
-    public void deleteAlias(PayloadObj<DeleteAliasPayload> obj) throws Exception {
-      final DeleteAliasPayload v2Body = obj.get();
-      final Map<String, Object> v1Params = v2Body.toMap(new HashMap<>());
-      v1Params.put(ACTION, CollectionAction.DELETEALIAS.toLower());
-
-      collectionsHandler.handleRequestBody(
-          wrapParams(obj.getRequest(), v1Params), obj.getResponse());
-    }
-
     @Command(name = V2_CREATE_COLLECTION_CMD)
     public void create(PayloadObj<CreatePayload> obj) throws Exception {
       final CreatePayload v2Body = obj.get();
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
index bcbe2ce66b0..8371e1041b1 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
@@ -210,6 +210,7 @@ import org.apache.solr.handler.admin.api.BalanceShardUniqueAPI;
 import org.apache.solr.handler.admin.api.CollectionPropertyAPI;
 import org.apache.solr.handler.admin.api.CollectionStatusAPI;
 import org.apache.solr.handler.admin.api.CreateShardAPI;
+import org.apache.solr.handler.admin.api.DeleteAliasAPI;
 import org.apache.solr.handler.admin.api.DeleteCollectionAPI;
 import org.apache.solr.handler.admin.api.DeleteNodeAPI;
 import org.apache.solr.handler.admin.api.DeleteReplicaAPI;
@@ -857,7 +858,16 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
           return result;
         }),
 
-    DELETEALIAS_OP(DELETEALIAS, (req, rsp, h) -> copy(req.getParams().required(), null, NAME)),
+    DELETEALIAS_OP(
+        DELETEALIAS,
+        (req, rsp, h) -> {
+          final DeleteAliasAPI deleteAliasAPI = new DeleteAliasAPI(h.coreContainer, req, rsp);
+          final SolrJerseyResponse response =
+              deleteAliasAPI.deleteAlias(
+                  req.getParams().required().get(NAME), req.getParams().get(ASYNC));
+          V2ApiUtils.squashIntoSolrResponseWithoutHeader(rsp, response);
+          return null;
+        }),
 
     /**
      * Change properties for an alias (use CREATEALIAS_OP to change the actual value of the alias)
@@ -2074,6 +2084,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
   public Collection<Class<? extends JerseyResource>> getJerseyResources() {
     return List.of(
         AddReplicaPropertyAPI.class,
+        DeleteAliasAPI.class,
         DeleteCollectionAPI.class,
         DeleteReplicaPropertyAPI.class,
         ListCollectionsAPI.class,
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/DeleteAliasAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/DeleteAliasAPI.java
new file mode 100644
index 00000000000..4b9a4480507
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/DeleteAliasAPI.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.solr.handler.admin.api;
+
+import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2;
+import static org.apache.solr.cloud.Overseer.QUEUE_OPERATION;
+import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
+import static org.apache.solr.common.params.CommonParams.NAME;
+import static org.apache.solr.handler.admin.CollectionsHandler.DEFAULT_COLLECTION_OP_TIMEOUT;
+import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.inject.Inject;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import org.apache.solr.client.solrj.SolrResponse;
+import org.apache.solr.common.cloud.ZkNodeProps;
+import org.apache.solr.common.params.CollectionParams;
+import org.apache.solr.core.CoreContainer;
+import org.apache.solr.handler.admin.CollectionsHandler;
+import org.apache.solr.jersey.AsyncJerseyResponse;
+import org.apache.solr.jersey.PermissionName;
+import org.apache.solr.jersey.SolrJerseyResponse;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
+
+@Path("/aliases/{aliasName}")
+public class DeleteAliasAPI extends AdminAPIBase {
+  @Inject
+  public DeleteAliasAPI(
+      CoreContainer coreContainer,
+      SolrQueryRequest solrQueryRequest,
+      SolrQueryResponse solrQueryResponse) {
+    super(coreContainer, solrQueryRequest, solrQueryResponse);
+  }
+
+  @DELETE
+  @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2})
+  @PermissionName(COLL_EDIT_PERM)
+  public SolrJerseyResponse deleteAlias(
+      @PathParam("aliasName") String aliasName, @QueryParam("async") String asyncId)
+      throws Exception {
+    final AsyncJerseyResponse response = instantiateJerseyResponse(AsyncJerseyResponse.class);
+    final CoreContainer coreContainer = fetchAndValidateZooKeeperAwareCoreContainer();
+
+    final ZkNodeProps remoteMessage = createRemoteMessage(aliasName, asyncId);
+    final SolrResponse remoteResponse =
+        CollectionsHandler.submitCollectionApiCommand(
+            coreContainer,
+            coreContainer.getDistributedCollectionCommandRunner(),
+            remoteMessage,
+            CollectionParams.CollectionAction.DELETEALIAS,
+            DEFAULT_COLLECTION_OP_TIMEOUT);
+    if (remoteResponse.getException() != null) {
+      throw remoteResponse.getException();
+    }
+
+    if (asyncId != null) {
+      response.requestId = asyncId;
+    }
+
+    return response;
+  }
+
+  public static ZkNodeProps createRemoteMessage(String aliasName, String asyncId) {
+    final Map<String, Object> remoteMessage = new HashMap<>();
+    remoteMessage.put(QUEUE_OPERATION, CollectionParams.CollectionAction.DELETEALIAS.toLower());
+    remoteMessage.put(NAME, aliasName);
+    if (asyncId != null) remoteMessage.put(ASYNC, asyncId);
+
+    return new ZkNodeProps(remoteMessage);
+  }
+}
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/DeleteAliasPayload.java b/solr/core/src/java/org/apache/solr/jersey/AsyncJerseyResponse.java
similarity index 71%
rename from solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/DeleteAliasPayload.java
rename to solr/core/src/java/org/apache/solr/jersey/AsyncJerseyResponse.java
index 4ccd0601a66..af08d227172 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/DeleteAliasPayload.java
+++ b/solr/core/src/java/org/apache/solr/jersey/AsyncJerseyResponse.java
@@ -14,14 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.solr.client.solrj.request.beans;
 
-import org.apache.solr.common.annotation.JsonProperty;
-import org.apache.solr.common.util.ReflectMapWriter;
+package org.apache.solr.jersey;
 
-public class DeleteAliasPayload implements ReflectMapWriter {
-  @JsonProperty(required = true)
-  public String name;
+import com.fasterxml.jackson.annotation.JsonProperty;
 
-  @JsonProperty public String async;
+public class AsyncJerseyResponse extends SolrJerseyResponse {
+  @JsonProperty("requestid")
+  public String requestId;
 }
diff --git a/solr/core/src/java/org/apache/solr/jersey/SubResponseAccumulatingJerseyResponse.java b/solr/core/src/java/org/apache/solr/jersey/SubResponseAccumulatingJerseyResponse.java
index ab476771d75..6f02e9b6b1c 100644
--- a/solr/core/src/java/org/apache/solr/jersey/SubResponseAccumulatingJerseyResponse.java
+++ b/solr/core/src/java/org/apache/solr/jersey/SubResponseAccumulatingJerseyResponse.java
@@ -27,10 +27,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
  * during the APIs execution. (e.g. the collection-deletion response itself contains the responses
  * from the 'UNLOAD' call send to each core.) This class encapsulates those responses as possible.
  */
-public class SubResponseAccumulatingJerseyResponse extends SolrJerseyResponse {
-
-  @JsonProperty("requestid")
-  public String requestId;
+public class SubResponseAccumulatingJerseyResponse extends AsyncJerseyResponse {
 
   // TODO The 'Object' value in this and the failure prop below have a more defined structure.
   //  Specifically, each value is a map whose keys are node names and whose values are full
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java b/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java
index 326066239ad..35847701431 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java
@@ -129,13 +129,6 @@ public class TestCollectionAPIs extends SolrTestCaseJ4 {
         "{create-alias:{name: aliasName , collections:[c1,c2] }}",
         "{operation : createalias, name: aliasName, collections:\"c1,c2\" }");
 
-    compareOutput(
-        apiBag,
-        "/collections",
-        POST,
-        "{delete-alias:{ name: aliasName}}",
-        "{operation : deletealias, name: aliasName}");
-
     compareOutput(
         apiBag, "/collections/collName", POST, "{reload:{}}", "{name:collName, operation :reload}");
 
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/V2CollectionsAPIMappingTest.java b/solr/core/src/test/org/apache/solr/handler/admin/V2CollectionsAPIMappingTest.java
index 2949fd38a67..ae099f24cb7 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/V2CollectionsAPIMappingTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/V2CollectionsAPIMappingTest.java
@@ -175,19 +175,6 @@ public class V2CollectionsAPIMappingTest extends V2ApiMappingTest<CollectionsHan
             RoutedAlias.CREATE_COLLECTION_PREFIX + ZkStateReader.REPLICATION_FACTOR));
   }
 
-  @Test
-  public void testDeleteAliasAllProperties() throws Exception {
-    final SolrParams v1Params =
-        captureConvertedV1Params(
-            "/collections",
-            "POST",
-            "{'delete-alias': {" + "'name': 'aliasName', " + "'async': 'requestTrackingId'" + "}}");
-
-    assertEquals(CollectionParams.CollectionAction.DELETEALIAS.lowerName, v1Params.get(ACTION));
-    assertEquals("aliasName", v1Params.get(CommonParams.NAME));
-    assertEquals("requestTrackingId", v1Params.get(CommonAdminParams.ASYNC));
-  }
-
   @Test
   public void testSetAliasAllProperties() throws Exception {
     final SolrParams v1Params =
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/DeleteAliasAPITest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/DeleteAliasAPITest.java
new file mode 100644
index 00000000000..2dcaf14d183
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/handler/admin/api/DeleteAliasAPITest.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.solr.handler.admin.api;
+
+import static org.apache.solr.cloud.Overseer.QUEUE_OPERATION;
+import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
+import static org.apache.solr.common.params.CoreAdminParams.NAME;
+
+import java.util.Map;
+import org.apache.solr.SolrTestCaseJ4;
+import org.junit.Test;
+
+/** Unit tests for {@link DeleteAliasAPI}. */
+public class DeleteAliasAPITest extends SolrTestCaseJ4 {
+
+  @Test
+  public void testConstructsValidRemoteMessage() {
+    Map<String, Object> props =
+        DeleteAliasAPI.createRemoteMessage("aliasName", null).getProperties();
+    assertEquals(2, props.size());
+    assertEquals("deletealias", props.get(QUEUE_OPERATION));
+    assertEquals("aliasName", props.get(NAME));
+
+    props = DeleteAliasAPI.createRemoteMessage("aliasName", "asyncId").getProperties();
+    assertEquals(3, props.size());
+    assertEquals("deletealias", props.get(QUEUE_OPERATION));
+    assertEquals("aliasName", props.get(NAME));
+    assertEquals("asyncId", props.get(ASYNC));
+  }
+}
diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/alias-management.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/alias-management.adoc
index bb1f98c98f6..b3f5d1d93a1 100644
--- a/solr/solr-ref-guide/modules/deployment-guide/pages/alias-management.adoc
+++ b/solr/solr-ref-guide/modules/deployment-guide/pages/alias-management.adoc
@@ -749,13 +749,7 @@ http://localhost:8983/solr/admin/collections?action=DELETEALIAS&name=testalias
 
 [source,bash]
 ----
-curl -X POST http://localhost:8983/api/collections -H 'Content-Type: application/json' -d '
-{
-  "delete-alias":{
-    "name":"testalias"
-  }
-}
-'
+curl -X DELETE http://localhost:8983/api/aliases/testalias
 ----
 ====
 --
@@ -770,7 +764,7 @@ curl -X POST http://localhost:8983/api/collections -H 'Content-Type: application
 s|Required |Default: none
 |===
 +
-The name of the alias to delete.
+The name of the alias to delete.  Specified in the path of v2 requests, and as an explicit request parameter for v1 requests.
 
 `async`::
 +