You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ji...@apache.org on 2019/04/12 17:49:52 UTC

[geode] branch develop updated: GEODE-6612: list regions in Management v2 api (#3445)

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

jinmeiliao pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new ae8ecb7  GEODE-6612: list regions in Management v2 api (#3445)
ae8ecb7 is described below

commit ae8ecb7737c2c099f509fb2ce3b9f1101b84a0ec
Author: jinmeiliao <ji...@pivotal.io>
AuthorDate: Fri Apr 12 10:49:40 2019 -0700

    GEODE-6612: list regions in Management v2 api (#3445)
    
    Co-authored-by: Peter Tran <pt...@pivotal.io>
---
 .../rest/ListRegionManagementDunitTest.java        | 148 +++++++++++++++++++++
 .../api/LocatorClusterManagementService.java       |  34 ++++-
 .../mutators/ConfigurationManager.java             |   2 +-
 .../mutators/RegionConfigManager.java              |  11 +-
 .../validators/RegionConfigValidator.java          |  10 ++
 .../validators/RegionConfigValidatorTest.java      |  34 +++--
 .../geode/cache/configuration/CacheElement.java    |   7 +
 .../management/api/ClusterManagementResult.java    |   3 +-
 .../internal/ClientClusterManagementService.java   |  18 +--
 .../configuration/CacheElementJsonMappingTest.java |  25 +++-
 .../ClientClusterManagementServiceDUnitTest.java   |  22 ++-
 .../rest/RegionManagementIntegrationTest.java      |  24 ++++
 .../controllers/MemberManagementController.java    |   7 +-
 .../controllers/RegionManagementController.java    |  19 +++
 14 files changed, 327 insertions(+), 37 deletions(-)

diff --git a/geode-assembly/src/distributedTest/java/org/apache/geode/management/internal/rest/ListRegionManagementDunitTest.java b/geode-assembly/src/distributedTest/java/org/apache/geode/management/internal/rest/ListRegionManagementDunitTest.java
new file mode 100644
index 0000000..911c319
--- /dev/null
+++ b/geode-assembly/src/distributedTest/java/org/apache/geode/management/internal/rest/ListRegionManagementDunitTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.geode.management.internal.rest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import org.apache.geode.cache.configuration.BasicRegionConfig;
+import org.apache.geode.cache.configuration.CacheElement;
+import org.apache.geode.management.api.ClusterManagementService;
+import org.apache.geode.management.client.ClusterManagementServiceProvider;
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+
+public class ListRegionManagementDunitTest {
+
+  @ClassRule
+  public static ClusterStartupRule cluster = new ClusterStartupRule();
+
+  private static MemberVM locator, server1, server2;
+
+  private static ClusterManagementService client;
+
+  @ClassRule
+  public static GfshCommandRule gfsh = new GfshCommandRule();
+
+  private static BasicRegionConfig filter;
+
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    locator = cluster.startLocatorVM(0, l -> l.withHttpService());
+    server1 = cluster.startServerVM(1, "group1", locator.getPort());
+    server2 = cluster.startServerVM(2, "group2", locator.getPort());
+
+    client = ClusterManagementServiceProvider.getService("localhost", locator.getHttpPort());
+    gfsh.connect(locator);
+
+    // create regions
+    BasicRegionConfig regionConfig = new BasicRegionConfig();
+    regionConfig.setName("customers1");
+    regionConfig.setGroup("group1");
+    client.create(regionConfig);
+
+    regionConfig = new BasicRegionConfig();
+    regionConfig.setName("customers2");
+    regionConfig.setGroup("group2");
+    client.create(regionConfig);
+
+    regionConfig = new BasicRegionConfig();
+    regionConfig.setName("customers");
+    client.create(regionConfig);
+  }
+
+  @Before
+  public void before() throws Exception {
+    filter = new BasicRegionConfig();
+  }
+
+  @Test
+  public void listAll() throws Exception {
+    // list all
+    List<CacheElement> regions = client.list(filter).getResult();
+    assertThat(regions.stream().map(CacheElement::getId).collect(Collectors.toList()))
+        .containsExactlyInAnyOrder("customers", "customers1", "customers2");
+    assertThat(regions.stream().map(CacheElement::getConfigGroup).collect(Collectors.toList()))
+        .containsExactlyInAnyOrder("cluster", "group1", "group2");
+  }
+
+  @Test
+  public void listClusterLevel() throws Exception {
+    // list cluster level only
+    filter.setGroup("cluster");
+    List<CacheElement> regions = client.list(filter).getResult();
+    assertThat(regions).hasSize(1);
+    assertThat(regions.get(0).getId()).isEqualTo("customers");
+    assertThat(regions.get(0).getConfigGroup()).isEqualTo("cluster");
+    assertThat(regions.get(0).getGroup()).isNull();
+  }
+
+  @Test
+  public void listGroup1() throws Exception {
+    // list group1
+    filter.setGroup("group1");
+    List<CacheElement> regions = client.list(filter).getResult();
+    assertThat(regions).hasSize(1);
+    assertThat(regions.get(0).getId()).isEqualTo("customers1");
+    assertThat(regions.get(0).getConfigGroup()).isEqualTo("group1");
+    assertThat(regions.get(0).getGroup()).isEqualTo("group1");
+  }
+
+  @Test
+  public void listGroup2() throws Exception {
+    // list group1
+    filter.setGroup("group2");
+    List<CacheElement> regions = client.list(filter).getResult();
+    assertThat(regions).hasSize(1);
+    assertThat(regions.get(0).getId()).isEqualTo("customers2");
+    assertThat(regions.get(0).getConfigGroup()).isEqualTo("group2");
+    assertThat(regions.get(0).getGroup()).isEqualTo("group2");
+  }
+
+  @Test
+  public void listNonExistentGroup() throws Exception {
+    // list non-existent group
+    filter.setGroup("group3");
+    List<CacheElement> regions = client.list(filter).getResult();
+    assertThat(regions).hasSize(0);
+  }
+
+  @Test
+  public void listRegionByName() throws Exception {
+    filter.setName("customers");
+    List<CacheElement> regions = client.list(filter).getResult();
+    assertThat(regions).hasSize(1);
+    assertThat(regions.get(0).getId()).isEqualTo("customers");
+    assertThat(regions.get(0).getConfigGroup()).isEqualTo("cluster");
+    assertThat(regions.get(0).getGroup()).isNull();
+  }
+
+  @Test
+  public void listNonExistentRegion() throws Exception {
+    // list non-existent region
+    filter.setName("customer3");
+    List<CacheElement> regions = client.list(filter).getResult();
+    assertThat(regions).hasSize(0);
+  }
+}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/api/LocatorClusterManagementService.java b/geode-core/src/main/java/org/apache/geode/management/internal/api/LocatorClusterManagementService.java
index 9051b34..23db474 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/api/LocatorClusterManagementService.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/api/LocatorClusterManagementService.java
@@ -17,6 +17,7 @@
 
 package org.apache.geode.management.internal.api;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -25,12 +26,14 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import org.apache.commons.lang3.NotImplementedException;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.Logger;
 
 import org.apache.geode.annotations.VisibleForTesting;
 import org.apache.geode.cache.configuration.BasicRegionConfig;
 import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.cache.configuration.CacheElement;
+import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.cache.execute.Function;
 import org.apache.geode.cache.execute.ResultCollector;
 import org.apache.geode.distributed.ConfigurationPersistenceService;
@@ -66,6 +69,7 @@ public class LocatorClusterManagementService implements ClusterManagementService
 
     // initialize the list of validators
     validators.put(BasicRegionConfig.class, new RegionConfigValidator(cache));
+    validators.put(RegionConfig.class, new RegionConfigValidator(cache));
   }
 
   @VisibleForTesting
@@ -79,7 +83,7 @@ public class LocatorClusterManagementService implements ClusterManagementService
 
   @Override
   public ClusterManagementResult create(CacheElement config) {
-    String group = config.getGroup();
+    String group = config.getConfigGroup();
 
     if (persistenceService == null) {
       return new ClusterManagementResult(false,
@@ -154,11 +158,33 @@ public class LocatorClusterManagementService implements ClusterManagementService
   @Override
   public ClusterManagementResult list(CacheElement filter) {
     ConfigurationManager manager = managers.get(filter.getClass());
-    List<CacheElement> listResults = manager.list(filter, null);
-
     ClusterManagementResult result = new ClusterManagementResult();
-    result.setResult(listResults);
 
+    if (filter instanceof MemberConfig) {
+      List<CacheElement> listResults = manager.list(filter, null);
+      result.setResult(listResults);
+      return result;
+    }
+
+    if (persistenceService == null) {
+      return new ClusterManagementResult(false,
+          "Cluster configuration service needs to be enabled");
+    }
+
+    List<CacheElement> elements = new ArrayList<>();
+    for (String group : persistenceService.getGroups()) {
+      if (StringUtils.isBlank(filter.getGroup()) || group.equals(filter.getConfigGroup())) {
+        CacheConfig currentPersistedConfig = persistenceService.getCacheConfig(group, true);
+        List<CacheElement> listInGroup = manager.list(filter, currentPersistedConfig);
+        // only set the group attribute when the config level is not in the cluster level
+        if (!group.equals("cluster")) {
+          listInGroup.stream().forEach(e -> e.setGroup(group));
+        }
+        elements.addAll(listInGroup);
+      }
+    }
+
+    result.setResult(elements);
     return result;
   }
 
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/mutators/ConfigurationManager.java b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/mutators/ConfigurationManager.java
index c3c1105..9862cff 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/mutators/ConfigurationManager.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/mutators/ConfigurationManager.java
@@ -37,5 +37,5 @@ public interface ConfigurationManager<T extends CacheElement> {
 
   void delete(T config, CacheConfig existing);
 
-  List<T> list(T filterConfig, CacheConfig existing);
+  List<? extends T> list(T filterConfig, CacheConfig existing);
 }
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/mutators/RegionConfigManager.java b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/mutators/RegionConfigManager.java
index cbb4d0b..aea6af6 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/mutators/RegionConfigManager.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/mutators/RegionConfigManager.java
@@ -18,11 +18,14 @@
 package org.apache.geode.management.internal.configuration.mutators;
 
 import java.util.List;
+import java.util.stream.Collectors;
 
 import org.apache.commons.lang3.NotImplementedException;
+import org.apache.commons.lang3.StringUtils;
 
 import org.apache.geode.cache.configuration.BasicRegionConfig;
 import org.apache.geode.cache.configuration.CacheConfig;
+import org.apache.geode.cache.configuration.RegionConfig;
 
 public class RegionConfigManager implements ConfigurationManager<BasicRegionConfig> {
 
@@ -44,7 +47,11 @@ public class RegionConfigManager implements ConfigurationManager<BasicRegionConf
   }
 
   @Override
-  public List<BasicRegionConfig> list(BasicRegionConfig config, CacheConfig existing) {
-    throw new NotImplementedException("Not implemented yet");
+  public List<RegionConfig> list(BasicRegionConfig filter, CacheConfig existing) {
+    if (StringUtils.isBlank(filter.getName())) {
+      return existing.getRegions();
+    }
+    return existing.getRegions().stream().filter(r -> filter.getName().equals(r.getName())).collect(
+        Collectors.toList());
   }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidator.java b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidator.java
index ca941fb..cedce5f 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidator.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidator.java
@@ -18,6 +18,7 @@ package org.apache.geode.management.internal.configuration.validators;
 import org.apache.geode.cache.configuration.BasicRegionConfig;
 import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.cache.configuration.CacheElement;
+import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.cache.configuration.RegionType;
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.cache.RegionNameValidation;
@@ -33,12 +34,21 @@ public class RegionConfigValidator implements ConfigurationValidator<BasicRegion
   @Override
   public void validate(BasicRegionConfig config)
       throws IllegalArgumentException {
+    if (config instanceof RegionConfig) {
+      throw new IllegalArgumentException("Use BasicRegionConfig to configure your region.");
+    }
+
     if (config.getName() == null) {
       throw new IllegalArgumentException("Name of the region has to be specified.");
     }
 
     RegionNameValidation.validate(config.getName());
 
+    if ("cluster".equalsIgnoreCase(config.getGroup())) {
+      throw new IllegalArgumentException(
+          "cluster is a reserved group name. Do not use it for member groups.");
+    }
+
     if (config.getType() == null) {
       RegionType defaultRegion = RegionType.PARTITION;
       config.setType(defaultRegion);
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidatorTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidatorTest.java
index df44a5e..1eac798 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidatorTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidatorTest.java
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.when;
 import org.junit.Before;
 import org.junit.Test;
 
+import org.apache.geode.cache.configuration.BasicRegionConfig;
 import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.cache.configuration.RegionType;
 import org.apache.geode.internal.cache.InternalCache;
@@ -37,7 +38,7 @@ import org.apache.geode.security.ResourcePermission;
 public class RegionConfigValidatorTest {
 
   private RegionConfigValidator validator;
-  private RegionConfig config;
+  private BasicRegionConfig config;
   private SecurityService securityService;
 
   @Before
@@ -46,7 +47,7 @@ public class RegionConfigValidatorTest {
     securityService = mock(SecurityService.class);
     when(cache.getSecurityService()).thenReturn(securityService);
     validator = new RegionConfigValidator(cache);
-    config = new RegionConfig();
+    config = new BasicRegionConfig();
   }
 
   @Test
@@ -66,7 +67,9 @@ public class RegionConfigValidatorTest {
     config.setType(RegionType.REPLICATE);
     validator.validate(config);
 
-    verify(securityService, times(0)).authorize(any());
+    verify(securityService, times(0)).authorize(
+        any(ResourcePermission.Resource.class),
+        any(ResourcePermission.Operation.class), any(ResourcePermission.Target.class));
     assertThat(config.getType()).isEqualTo("REPLICATE");
   }
 
@@ -84,7 +87,6 @@ public class RegionConfigValidatorTest {
     config.setName("regionName");
     validator.validate(config);
 
-    verify(securityService, times(0)).authorize(any());
     assertThat(config.getType()).isEqualTo("PARTITION");
   }
 
@@ -93,8 +95,6 @@ public class RegionConfigValidatorTest {
     assertThatThrownBy(() -> validator.validate(config)).isInstanceOf(
         IllegalArgumentException.class)
         .hasMessageContaining("Name of the region has to be specified");
-
-    verify(securityService, times(0)).authorize(any());
   }
 
   @Test
@@ -103,8 +103,6 @@ public class RegionConfigValidatorTest {
     assertThatThrownBy(() -> validator.validate(config)).isInstanceOf(
         IllegalArgumentException.class)
         .hasMessageContaining("Region names may not begin with a double-underscore");
-
-    verify(securityService, times(0)).authorize(any());
   }
 
   @Test
@@ -114,7 +112,25 @@ public class RegionConfigValidatorTest {
         IllegalArgumentException.class)
         .hasMessageContaining(
             "Region names may only be alphanumeric and may contain hyphens or underscores");
+  }
 
-    verify(securityService, times(0)).authorize(any());
+  @Test
+  public void invalidGroup() throws Exception {
+    config.setName("test");
+    config.setGroup("cluster");
+    assertThatThrownBy(() -> validator.validate(config)).isInstanceOf(
+        IllegalArgumentException.class)
+        .hasMessageContaining(
+            "cluster is a reserved group name");
+  }
+
+  @Test
+  public void invalidObject() throws Exception {
+    RegionConfig config = new RegionConfig();
+    config.setName("test");
+    assertThatThrownBy(() -> validator.validate(config)).isInstanceOf(
+        IllegalArgumentException.class)
+        .hasMessageContaining(
+            "Use BasicRegionConfig to configure your region");
   }
 }
diff --git a/geode-management/src/main/java/org/apache/geode/cache/configuration/CacheElement.java b/geode-management/src/main/java/org/apache/geode/cache/configuration/CacheElement.java
index 7c01106..4462f57 100644
--- a/geode-management/src/main/java/org/apache/geode/cache/configuration/CacheElement.java
+++ b/geode-management/src/main/java/org/apache/geode/cache/configuration/CacheElement.java
@@ -22,6 +22,7 @@ import java.util.List;
 
 import javax.xml.bind.annotation.XmlTransient;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import org.apache.commons.lang3.StringUtils;
 
@@ -47,6 +48,12 @@ public abstract class CacheElement implements Identifiable<String>, Serializable
 
   @XmlTransient
   public String getGroup() {
+    return group;
+  }
+
+  @XmlTransient
+  @JsonIgnore
+  public String getConfigGroup() {
     if (StringUtils.isBlank(group)) {
       return "cluster";
     }
diff --git a/geode-management/src/main/java/org/apache/geode/management/api/ClusterManagementResult.java b/geode-management/src/main/java/org/apache/geode/management/api/ClusterManagementResult.java
index 2f61e8d..0f825f2 100644
--- a/geode-management/src/main/java/org/apache/geode/management/api/ClusterManagementResult.java
+++ b/geode-management/src/main/java/org/apache/geode/management/api/ClusterManagementResult.java
@@ -21,9 +21,10 @@ import java.util.Map;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 
+import org.apache.geode.annotations.Experimental;
 import org.apache.geode.cache.configuration.CacheElement;
 
-
+@Experimental
 public class ClusterManagementResult {
   // this error code should include a one-to-one mapping to the http status code returned
   // by the controller
diff --git a/geode-management/src/main/java/org/apache/geode/management/internal/ClientClusterManagementService.java b/geode-management/src/main/java/org/apache/geode/management/internal/ClientClusterManagementService.java
index 0a18b11..7c3b1d1 100644
--- a/geode-management/src/main/java/org/apache/geode/management/internal/ClientClusterManagementService.java
+++ b/geode-management/src/main/java/org/apache/geode/management/internal/ClientClusterManagementService.java
@@ -42,9 +42,9 @@ import org.apache.geode.management.api.RestfulEndpoint;
  * <p/>
  * In order to manipulate Geode components (Regions, etc.) clients can construct instances of {@link
  * CacheElement}s and call the corresponding
- * {@link ClientClusterManagementService#create(CacheElement,
- * String)}, {@link ClientClusterManagementService#delete(CacheElement, String)} or {@link
- * ClientClusterManagementService#update(CacheElement, String)} method. The returned {@link
+ * {@link ClientClusterManagementService#create(CacheElement)},
+ * {@link ClientClusterManagementService#delete(CacheElement)} or
+ * {@link ClientClusterManagementService#update(CacheElement)} method. The returned {@link
  * ClusterManagementResult} will contain all necessary information about the outcome of the call.
  * This will include the result of persisting the config as part of the cluster configuration as
  * well as creating the actual component in the cluster.
@@ -127,18 +127,10 @@ public class ClientClusterManagementService implements ClusterManagementService
   @Override
   public ClusterManagementResult list(CacheElement config) {
     String endPoint = getEndpoint(config);
-    String id = config.getId();
-
-    // return restTemplate
-    // .getForEntity(VERSION + endPoint + ((id == null) ? "" : "/{id}"),
-    // ClusterManagementResult.class, id)
-    // .getBody();
-
     return restTemplate
-        .getForEntity(VERSION + endPoint + ((id == null) ? "" : "/?id=" + id),
-            ClusterManagementResult.class)
+        .getForEntity(VERSION + endPoint + "/?id={id}&group={group}",
+            ClusterManagementResult.class, config.getId(), config.getGroup())
         .getBody();
-
   }
 
   public RestTemplate getRestTemplate() {
diff --git a/geode-management/src/test/java/org/apache/geode/cache/configuration/CacheElementJsonMappingTest.java b/geode-management/src/test/java/org/apache/geode/cache/configuration/CacheElementJsonMappingTest.java
index 8187c28..1aaf484 100644
--- a/geode-management/src/test/java/org/apache/geode/cache/configuration/CacheElementJsonMappingTest.java
+++ b/geode-management/src/test/java/org/apache/geode/cache/configuration/CacheElementJsonMappingTest.java
@@ -45,7 +45,7 @@ public class CacheElementJsonMappingTest {
   }
 
   @Test
-  public void serializeRegion() throws Exception {
+  public void serializeBasicRegion() throws Exception {
     String json = mapper.writeValueAsString(region);
     System.out.println(json);
     assertThat(json).contains("class").contains("\"name\":\"test\"");
@@ -55,6 +55,18 @@ public class CacheElementJsonMappingTest {
   }
 
   @Test
+  public void serializeRegion() throws Exception {
+    RegionConfig value = new RegionConfig();
+    value.setName("test");
+    String json = mapper.writeValueAsString(value);
+    System.out.println(json);
+    assertThat(json).contains("class").contains("\"name\":\"test\"");
+
+    RegionConfig config = mapper.readValue(json, RegionConfig.class);
+    assertThat(config.getName()).isEqualTo(region.getName());
+  }
+
+  @Test
   public void serializeMember() throws Exception {
     String json = mapper.writeValueAsString(member);
     System.out.println(json);
@@ -77,6 +89,8 @@ public class CacheElementJsonMappingTest {
 
     ClusterManagementResult result1 = mapper.readValue(json, ClusterManagementResult.class);
     assertThat(result1.getResult()).hasSize(2);
+    assertThat(result1.getResult().get(0)).isInstanceOf(BasicRegionConfig.class);
+    assertThat(result1.getResult().get(1)).isInstanceOf(MemberConfig.class);
   }
 
   @Test
@@ -85,4 +99,13 @@ public class CacheElementJsonMappingTest {
     BasicRegionConfig config = mapper.readValue(json, BasicRegionConfig.class);
     assertThat(config.getName()).isEqualTo("test");
   }
+
+  @Test
+  public void getGroup() throws Exception {
+    assertThat(region.getGroup()).isNull();
+    assertThat(region.getConfigGroup()).isEqualTo("cluster");
+
+    String json = mapper.writeValueAsString(region);
+    assertThat(json).contains("\"group\":null");
+  }
 }
diff --git a/geode-web-management/src/distributedTest/java/org/apache/geode/management/client/ClientClusterManagementServiceDUnitTest.java b/geode-web-management/src/distributedTest/java/org/apache/geode/management/client/ClientClusterManagementServiceDUnitTest.java
index 16914c4..9891df4 100644
--- a/geode-web-management/src/distributedTest/java/org/apache/geode/management/client/ClientClusterManagementServiceDUnitTest.java
+++ b/geode-web-management/src/distributedTest/java/org/apache/geode/management/client/ClientClusterManagementServiceDUnitTest.java
@@ -16,8 +16,11 @@
 package org.apache.geode.management.client;
 
 
+import static org.apache.geode.test.junit.assertions.ClusterManagementResultAssert.assertManagementResult;
 import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
 
+import java.util.List;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -30,6 +33,8 @@ import org.springframework.test.context.web.WebAppConfiguration;
 import org.springframework.web.context.WebApplicationContext;
 
 import org.apache.geode.cache.configuration.BasicRegionConfig;
+import org.apache.geode.cache.configuration.CacheElement;
+import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.cache.configuration.RegionType;
 import org.apache.geode.management.api.ClusterManagementResult;
 import org.apache.geode.management.api.ClusterManagementService;
@@ -64,18 +69,29 @@ public class ClientClusterManagementServiceDUnitTest {
 
   @Test
   @WithMockUser
-  public void createRegion() {
+  public void createAndListRegion() {
     BasicRegionConfig region = new BasicRegionConfig();
     region.setName("customer");
-    region.setType(RegionType.REPLICATE_PERSISTENT);
+    region.setType(RegionType.REPLICATE);
 
     ClusterManagementResult result = client.create(region);
 
     // in StressNewTest, this will be run multiple times without restarting the locator
-    assertThat(result.getStatusCode()).isIn(ClusterManagementResult.StatusCode.OK,
+    assertManagementResult(result).hasStatusCode(ClusterManagementResult.StatusCode.OK,
         ClusterManagementResult.StatusCode.ENTITY_EXISTS);
+
+    // list region when regions are not created in a group
+    BasicRegionConfig noFilter = new BasicRegionConfig();
+    ClusterManagementResult list = client.list(noFilter);
+    List<CacheElement> regions = list.getResult();
+    assertThat(regions.size()).isEqualTo(1);
+    RegionConfig cacheElement = (RegionConfig) regions.get(0);
+    assertThat(cacheElement.getId()).isEqualTo("customer");
+    assertThat(cacheElement.getType()).isEqualTo("REPLICATE");
+    assertThat(cacheElement.getConfigGroup()).isEqualTo("cluster");
   }
 
+
   @Test
   @WithMockUser
   public void sanityCheck() {
diff --git a/geode-web-management/src/integrationTest/java/org/apache/geode/management/internal/rest/RegionManagementIntegrationTest.java b/geode-web-management/src/integrationTest/java/org/apache/geode/management/internal/rest/RegionManagementIntegrationTest.java
index b61016b..f6c341c 100644
--- a/geode-web-management/src/integrationTest/java/org/apache/geode/management/internal/rest/RegionManagementIntegrationTest.java
+++ b/geode-web-management/src/integrationTest/java/org/apache/geode/management/internal/rest/RegionManagementIntegrationTest.java
@@ -30,6 +30,7 @@ import org.springframework.test.context.web.WebAppConfiguration;
 import org.springframework.web.context.WebApplicationContext;
 
 import org.apache.geode.cache.configuration.BasicRegionConfig;
+import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.cache.configuration.RegionType;
 import org.apache.geode.management.api.ClusterManagementResult;
 import org.apache.geode.management.api.ClusterManagementService;
@@ -82,6 +83,29 @@ public class RegionManagementIntegrationTest {
   }
 
   @Test
+  public void invalidGroup() throws Exception {
+    BasicRegionConfig regionConfig = new BasicRegionConfig();
+    regionConfig.setName("customers");
+    regionConfig.setGroup("cluster");
+
+    assertManagementResult(client.create(regionConfig))
+        .failed()
+        .hasStatusCode(ClusterManagementResult.StatusCode.ILLEGAL_ARGUMENT)
+        .containsStatusMessage("cluster is a reserved group name");
+  }
+
+  @Test
+  public void invalidConfigObject() throws Exception {
+    RegionConfig config = new RegionConfig();
+    config.setName("customers");
+    assertManagementResult(client.create(config))
+        .failed()
+        .hasStatusCode(ClusterManagementResult.StatusCode.ILLEGAL_ARGUMENT)
+        .containsStatusMessage("Use BasicRegionConfig to configure your region");
+  }
+
+
+  @Test
   @WithMockUser
   public void ping() throws Exception {
     context.perform(get("/v2/ping"))
diff --git a/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/controllers/MemberManagementController.java b/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/controllers/MemberManagementController.java
index 4e4c075..2a0cb2c 100644
--- a/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/controllers/MemberManagementController.java
+++ b/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/controllers/MemberManagementController.java
@@ -18,6 +18,7 @@ package org.apache.geode.management.internal.rest.controllers;
 import static org.apache.geode.management.configuration.MemberConfig.MEMBER_CONFIG_ENDPOINT;
 import static org.apache.geode.management.internal.rest.controllers.AbstractManagementController.MANAGEMENT_API_VERSION;
 
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -37,7 +38,7 @@ public class MemberManagementController extends AbstractManagementController {
   @PreAuthorize("@securityService.authorize('CLUSTER', 'READ')")
   @RequestMapping(method = RequestMethod.GET, value = MEMBER_CONFIG_ENDPOINT + "/{id}")
   public ResponseEntity<ClusterManagementResult> getMember(
-      @PathVariable(name = "id", required = false) String id) {
+      @PathVariable(name = "id") String id) {
     MemberConfig config = new MemberConfig();
     config.setId(id);
     ClusterManagementResult result = clusterManagementService.list(config);
@@ -53,9 +54,9 @@ public class MemberManagementController extends AbstractManagementController {
   @PreAuthorize("@securityService.authorize('CLUSTER', 'READ')")
   @RequestMapping(method = RequestMethod.GET, value = MEMBER_CONFIG_ENDPOINT)
   public ResponseEntity<ClusterManagementResult> listMembers(
-      @RequestParam(required = false) String id) {
+      @RequestParam(required = false) String id, @RequestParam(required = false) String group) {
     MemberConfig filter = new MemberConfig();
-    if (id != null) {
+    if (StringUtils.isNotBlank(id)) {
       filter.setId(id);
     }
     ClusterManagementResult result = clusterManagementService.list(filter);
diff --git a/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/controllers/RegionManagementController.java b/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/controllers/RegionManagementController.java
index 150d5d6..d1881f1 100644
--- a/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/controllers/RegionManagementController.java
+++ b/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/controllers/RegionManagementController.java
@@ -21,6 +21,7 @@ import static org.apache.geode.management.internal.rest.controllers.AbstractMana
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -28,6 +29,7 @@ import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
 
 import org.apache.geode.cache.configuration.BasicRegionConfig;
 import org.apache.geode.management.api.ClusterManagementResult;
@@ -51,4 +53,21 @@ public class RegionManagementController extends AbstractManagementController {
     return new ResponseEntity<>(result,
         result.isSuccessful() ? HttpStatus.CREATED : HttpStatus.INTERNAL_SERVER_ERROR);
   }
+
+  @PreAuthorize("@securityService.authorize('CLUSTER', 'READ')")
+  @RequestMapping(method = RequestMethod.GET, value = REGION_CONFIG_ENDPOINT)
+  public ResponseEntity<ClusterManagementResult> listRegion(
+      @RequestParam(required = false) String id,
+      @RequestParam(required = false) String group) {
+    BasicRegionConfig filter = new BasicRegionConfig();
+    if (StringUtils.isNotBlank(id)) {
+      filter.setName(id);
+    }
+    if (StringUtils.isNotBlank(group)) {
+      filter.setGroup(group);
+    }
+    ClusterManagementResult result = clusterManagementService.list(filter);
+    return new ResponseEntity<>(result,
+        result.isSuccessful() ? HttpStatus.OK : HttpStatus.INTERNAL_SERVER_ERROR);
+  }
 }