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

jxue pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git

commit 07168eee784751661c298f888321c1493df1a46a
Author: narendly <[email protected]>
AuthorDate: Mon Feb 25 18:12:41 2019 -0800

    [HELIX-804] REST: Support customFields in enabling/disabling maintenance 
mode
    
    To improve operability around maintenance mode, we want to allow users to 
specify a reason or customFields (KV mappings) when they enable/disable 
maintenance mode.
        Changelist:
        1. Modify logic in ClusterAccessor so that the user could pass in 
customFields QueryParam in a JSON string
        2. Add an integration test that verifies the fields have been set
---
 .../server/resources/helix/ClusterAccessor.java    | 24 ++++++-----
 .../helix/rest/server/TestClusterAccessor.java     | 48 +++++++++++++++++-----
 2 files changed, 52 insertions(+), 20 deletions(-)

diff --git 
a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ClusterAccessor.java
 
b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ClusterAccessor.java
index febe65b..f24076a 100644
--- 
a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ClusterAccessor.java
+++ 
b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/helix/ClusterAccessor.java
@@ -49,6 +49,7 @@ import org.apache.helix.model.Message;
 import org.apache.helix.model.StateModelDefinition;
 import org.apache.helix.model.builder.HelixConfigScopeBuilder;
 import org.apache.helix.tools.ClusterSetup;
+import org.codehaus.jackson.type.TypeReference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -156,7 +157,7 @@ public class ClusterAccessor extends AbstractHelixResource {
   @Path("{clusterId}")
   public Response updateCluster(@PathParam("clusterId") String clusterId,
       @QueryParam("command") String commandStr, @QueryParam("superCluster") 
String superCluster,
-      String content) {
+      @QueryParam("customFields") String customFields, String content) {
     Command command;
     try {
       command = getCommand(commandStr);
@@ -206,22 +207,25 @@ public class ClusterAccessor extends 
AbstractHelixResource {
         return serverError(ex);
       }
       break;
+
     case enableMaintenanceMode:
-      try {
-        helixAdmin.enableMaintenanceMode(clusterId, true, content);
-      } catch (Exception ex) {
-        _logger.error("Failed to enable maintenance mode " + clusterId);
-        return serverError(ex);
-      }
-      break;
     case disableMaintenanceMode:
       try {
-        helixAdmin.enableMaintenanceMode(clusterId, false);
+        Map<String, String> customFieldsMap = new HashMap<>();
+        if (customFields != null && !customFields.isEmpty()) {
+          customFieldsMap = OBJECT_MAPPER.readValue(customFields,
+              new TypeReference<HashMap<String, String>>() {
+              });
+        }
+        helixAdmin.manuallyEnableMaintenanceMode(clusterId,
+            command == Command.enableMaintenanceMode, content, 
customFieldsMap);
       } catch (Exception ex) {
-        _logger.error("Failed to disable maintenance mode " + clusterId);
+        _logger.error("Failed to disable maintenance mode for cluster {}. 
Exception: {}", clusterId,
+            ex);
         return serverError(ex);
       }
       break;
+
     default:
       return badRequest("Unsupported command " + command);
     }
diff --git 
a/helix-rest/src/test/java/org/apache/helix/rest/server/TestClusterAccessor.java
 
b/helix-rest/src/test/java/org/apache/helix/rest/server/TestClusterAccessor.java
index 46be8c2..b2a14cf 100644
--- 
a/helix-rest/src/test/java/org/apache/helix/rest/server/TestClusterAccessor.java
+++ 
b/helix-rest/src/test/java/org/apache/helix/rest/server/TestClusterAccessor.java
@@ -22,6 +22,7 @@ package org.apache.helix.rest.server;
 import com.google.common.collect.ImmutableMap;
 import com.sun.research.ws.wadl.HTTPMethods;
 import java.io.IOException;
+import java.net.URLEncoder;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -52,7 +53,6 @@ import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 public class TestClusterAccessor extends AbstractTestClass {
-  ObjectMapper _mapper = new ObjectMapper();
 
   @BeforeClass
   public void beforeClass() {
@@ -68,12 +68,12 @@ public class TestClusterAccessor extends AbstractTestClass {
 
     _auditLogger.clearupLogs();
     String body = get("clusters", Response.Status.OK.getStatusCode(), true);
-    JsonNode node = _mapper.readTree(body);
+    JsonNode node = OBJECT_MAPPER.readTree(body);
     String clustersStr = 
node.get(ClusterAccessor.ClusterProperties.clusters.name()).toString();
     Assert.assertNotNull(clustersStr);
 
-    Set<String> clusters = _mapper.readValue(clustersStr,
-        _mapper.getTypeFactory().constructCollectionType(Set.class, 
String.class));
+    Set<String> clusters = OBJECT_MAPPER.readValue(clustersStr,
+        OBJECT_MAPPER.getTypeFactory().constructCollectionType(Set.class, 
String.class));
     Assert.assertEquals(clusters, _clusters,
         "clusters from response: " + clusters + " vs clusters actually: " + 
_clusters);
 
@@ -255,7 +255,7 @@ public class TestClusterAccessor extends AbstractTestClass {
     Assert.assertNotNull(signal);
     Assert.assertEquals(reason, signal.getReason());
     post("clusters/" + cluster, ImmutableMap.of("command", 
"disableMaintenanceMode"),
-        Entity.entity(new String(), MediaType.APPLICATION_JSON_TYPE),
+        Entity.entity("", MediaType.APPLICATION_JSON_TYPE),
         Response.Status.OK.getStatusCode());
     
Assert.assertNull(accessor.getProperty(accessor.keyBuilder().maintenance()));
   }
@@ -304,13 +304,12 @@ public class TestClusterAccessor extends 
AbstractTestClass {
         Entity.entity(reason, MediaType.APPLICATION_JSON_TYPE), 
Response.Status.OK.getStatusCode());
 
     // Get the maintenance history JSON's last entry
-    String maintenanceHistory = get("clusters/" + cluster + 
"/controller/maintenanceHistory",
-        Response.Status.OK.getStatusCode(), true);
+    String maintenanceHistory =
+        get("clusters/" + cluster + "/controller/maintenanceHistory", 
Response.Status.OK.getStatusCode(), true);
     Map<String, Object> maintenanceHistoryMap =
         OBJECT_MAPPER.readValue(maintenanceHistory, new 
TypeReference<HashMap<String, Object>>() {
         });
-    Object maintenanceHistoryList =
-        
maintenanceHistoryMap.get(AbstractResource.Properties.maintenanceHistory.name());
+    Object maintenanceHistoryList = 
maintenanceHistoryMap.get(AbstractResource.Properties.maintenanceHistory.name());
     Assert.assertNotNull(maintenanceHistoryList);
     List<?> list = (List<?>) maintenanceHistoryList;
     Assert.assertTrue(list.size() > 0);
@@ -320,6 +319,35 @@ public class TestClusterAccessor extends AbstractTestClass 
{
     Assert.assertTrue(lastMaintenanceEntry.contains(reason));
   }
 
+  @Test(dependsOnMethods = "testEnableDisableMaintenanceMode")
+  public void testEnableDisableMaintenanceModeWithCustomFields() {
+    System.out.println("Start test :" + TestHelper.getTestMethodName());
+    String cluster = _clusters.iterator().next();
+    String reason = "Test reason";
+    HelixDataAccessor accessor = new ZKHelixDataAccessor(cluster, 
_baseAccessor);
+
+    String customFields = "{\"key1\":\"value1\",\"key2\":\"value2\"}";
+    // Note that URLEncoder.encode has to be used due to a Jersey bug
+    // See https://github.com/Mercateo/rest-schemagen/issues/51
+    post("clusters/" + cluster,
+        ImmutableMap.of("command", "enableMaintenanceMode", "customFields",
+            URLEncoder.encode(customFields)),
+        Entity.entity(reason, MediaType.APPLICATION_JSON_TYPE), 
Response.Status.OK.getStatusCode());
+
+    MaintenanceSignal signal = 
accessor.getProperty(accessor.keyBuilder().maintenance());
+    Assert.assertNotNull(signal);
+    Assert.assertEquals(reason, signal.getReason());
+    Assert.assertEquals(signal.getTriggeringEntity(), 
MaintenanceSignal.TriggeringEntity.USER);
+    Map<String, String> simpleFields = signal.getRecord().getSimpleFields();
+    Assert.assertEquals(simpleFields.get("key1"), "value1");
+    Assert.assertEquals(simpleFields.get("key2"), "value2");
+
+    post("clusters/" + cluster, ImmutableMap.of("command", 
"disableMaintenanceMode"),
+        Entity.entity("", MediaType.APPLICATION_JSON_TYPE), 
Response.Status.OK.getStatusCode());
+    Assert.assertFalse(
+        
accessor.getBaseDataAccessor().exists(accessor.keyBuilder().maintenance().getPath(),
 0));
+  }
+
   private ClusterConfig getClusterConfigFromRest(String cluster) throws 
IOException {
     String body = get("clusters/" + cluster + "/configs", 
Response.Status.OK.getStatusCode(), true);
 
@@ -337,7 +365,7 @@ public class TestClusterAccessor extends AbstractTestClass {
       Command command) throws IOException {
     _auditLogger.clearupLogs();
     Entity entity = Entity
-        .entity(_mapper.writeValueAsString(newConfig.getRecord()), 
MediaType.APPLICATION_JSON_TYPE);
+        .entity(OBJECT_MAPPER.writeValueAsString(newConfig.getRecord()), 
MediaType.APPLICATION_JSON_TYPE);
     post("clusters/" + cluster + "/configs", ImmutableMap.of("command", 
command.name()), entity,
         Response.Status.OK.getStatusCode());
 

Reply via email to