HBASE-24431 RSGroupInfo add configuration map to store something extra (#2031)

Signed-off-by: Guanghao Zhang <zghao@apache.org>
This commit is contained in:
XinSun 2020-07-08 14:39:41 +08:00 committed by GitHub
parent f771fd26b4
commit 5fcffae5db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 416 additions and 7 deletions

View File

@ -19,6 +19,10 @@
package org.apache.hadoop.hbase.rsgroup;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
@ -41,18 +45,22 @@ public class RSGroupInfo {
// Keep tables sorted too.
private final SortedSet<TableName> tables;
private final Map<String, String> configuration;
public RSGroupInfo(String name) {
this(name, new TreeSet<Address>(), new TreeSet<TableName>());
this(name, new TreeSet<>(), new TreeSet<>());
}
RSGroupInfo(String name, SortedSet<Address> servers, SortedSet<TableName> tables) {
this.name = name;
this.servers = (servers == null) ? new TreeSet<>() : new TreeSet<>(servers);
this.tables = (tables == null) ? new TreeSet<>() : new TreeSet<>(tables);
configuration = new HashMap<>();
}
public RSGroupInfo(RSGroupInfo src) {
this(src.name, src.servers, src.tables);
src.configuration.forEach(this::setConfiguration);
}
/**
@ -121,6 +129,30 @@ public class RSGroupInfo {
return tables.remove(table);
}
/**
* Getter for fetching an unmodifiable {@link #configuration} map.
*/
public Map<String, String> getConfiguration() {
// shallow pointer copy
return Collections.unmodifiableMap(configuration);
}
/**
* Setter for storing a configuration setting in {@link #configuration} map.
* @param key Config key.
* @param value String value.
*/
public void setConfiguration(String key, String value) {
configuration.put(key, Objects.requireNonNull(value));
}
/**
* Remove a config setting represented by the key from the {@link #configuration} map
*/
public void removeConfiguration(final String key) {
configuration.remove(key);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();

View File

@ -31,5 +31,6 @@ message RSGroupInfo {
required string name = 1;
repeated ServerName servers = 4;
repeated TableName tables = 3;
repeated NameStringPair configuration = 5;
}

View File

@ -19,6 +19,7 @@ package org.apache.hadoop.hbase.rsgroup;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.hadoop.hbase.TableName;
@ -105,4 +106,12 @@ public interface RSGroupAdmin {
* @param newName new rsgroup name
*/
void renameRSGroup(String oldName, String newName) throws IOException;
/**
* Update RSGroup configuration
* @param groupName the group name
* @param configuration new configuration of the group name to be set
* @throws IOException if a remote or network exception occurs
*/
void updateRSGroupConfig(String groupName, Map<String, String> configuration) throws IOException;
}

View File

@ -22,6 +22,7 @@ import com.google.protobuf.ServiceException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.hadoop.hbase.TableName;
@ -31,6 +32,7 @@ import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.NameStringPair;
import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.AddRSGroupRequest;
import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.BalanceRSGroupRequest;
import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoOfServerRequest;
@ -47,6 +49,7 @@ import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RSGroupAdmi
import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveRSGroupRequest;
import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveServersRequest;
import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RenameRSGroupRequest;
import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.UpdateRSGroupConfigRequest;
import org.apache.hadoop.hbase.protobuf.generated.RSGroupProtos;
import org.apache.yetus.audience.InterfaceAudience;
@ -249,4 +252,21 @@ public class RSGroupAdminClient implements RSGroupAdmin {
throw ProtobufUtil.handleRemoteException(e);
}
}
@Override
public void updateRSGroupConfig(String groupName, Map<String, String> configuration)
throws IOException {
UpdateRSGroupConfigRequest.Builder builder = UpdateRSGroupConfigRequest.newBuilder()
.setGroupName(groupName);
if (configuration != null) {
configuration.entrySet().forEach(e ->
builder.addConfiguration(NameStringPair.newBuilder().setName(e.getKey())
.setValue(e.getValue()).build()));
}
try {
stub.updateRSGroupConfig(null, builder.build());
} catch (ServiceException e) {
throw ProtobufUtil.handleRemoteException(e);
}
}
}

View File

@ -26,6 +26,7 @@ import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@ -81,6 +82,8 @@ import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveServe
import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveServersResponse;
import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RenameRSGroupRequest;
import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RenameRSGroupResponse;
import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.UpdateRSGroupConfigRequest;
import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.UpdateRSGroupConfigResponse;
import org.apache.hadoop.hbase.protobuf.generated.TableProtos;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.UserProvider;
@ -90,6 +93,8 @@ import org.apache.hadoop.util.Shell.ShellCommandExecutor;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hbase.thirdparty.com.google.common.collect.Maps;
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
// TODO: Encapsulate MasterObserver functions into separate subclass.
@ -425,6 +430,29 @@ public class RSGroupAdminEndpoint implements MasterCoprocessor, MasterObserver {
}
done.run(builder.build());
}
@Override
public void updateRSGroupConfig(RpcController controller, UpdateRSGroupConfigRequest request,
RpcCallback<UpdateRSGroupConfigResponse> done) {
UpdateRSGroupConfigResponse.Builder builder = UpdateRSGroupConfigResponse.newBuilder();
String groupName = request.getGroupName();
Map<String, String> configuration = Maps.newHashMap();
request.getConfigurationList().forEach(p -> configuration.put(p.getName(), p.getValue()));
LOG.info("{} update rsgroup {} configuration {}", master.getClientIdAuditPrefix(), groupName,
configuration);
try {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preUpdateRSGroupConfig(groupName, configuration);
}
groupAdminServer.updateRSGroupConfig(groupName, configuration);
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().postUpdateRSGroupConfig(groupName, configuration);
}
} catch (IOException e) {
CoprocessorRpcUtils.setControllerException(controller, e);
}
done.run(builder.build());
}
}
boolean rsgroupHasServersOnline(TableDescriptor desc) throws IOException {

View File

@ -532,6 +532,14 @@ public class RSGroupAdminServer implements RSGroupAdmin {
}
}
@Override
public void updateRSGroupConfig(String groupName, Map<String, String> configuration)
throws IOException {
synchronized (rsGroupInfoManager) {
rsGroupInfoManager.updateRSGroupConfig(groupName, configuration);
}
}
private Map<String, RegionState> rsGroupGetRegionsInTransition(String groupName)
throws IOException {
Map<String, RegionState> rit = Maps.newTreeMap();

View File

@ -21,6 +21,7 @@ package org.apache.hadoop.hbase.rsgroup;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.hadoop.hbase.NamespaceDescriptor;
@ -139,4 +140,12 @@ public interface RSGroupInfoManager {
* @return {@link RSGroupInfo} which table should belong to
*/
RSGroupInfo determineRSGroupInfoForTable(TableName tableName) throws IOException;
/**
* Update RSGroup configuration
* @param groupName the group name
* @param configuration new configuration of the group name to be set
* @throws IOException if a remote or network exception occurs
*/
void updateRSGroupConfig(String groupName, Map<String, String> configuration) throws IOException;
}

View File

@ -32,6 +32,7 @@ import java.util.OptionalLong;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Coprocessor;
import org.apache.hadoop.hbase.DoNotRetryIOException;
@ -452,6 +453,16 @@ final class RSGroupInfoManagerImpl implements RSGroupInfoManager {
return getRSGroup(RSGroupInfo.DEFAULT_GROUP);
}
@Override
public void updateRSGroupConfig(String groupName, Map<String, String> configuration)
throws IOException {
RSGroupInfo rsGroupInfo = getRSGroupInfo(groupName);
new HashSet<>(rsGroupInfo.getConfiguration().keySet())
.forEach(rsGroupInfo::removeConfiguration);
configuration.forEach(rsGroupInfo::setConfiguration);
flushConfig();
}
List<RSGroupInfo> retrieveGroupListFromGroupTable() throws IOException {
List<RSGroupInfo> rsGroupInfoList = Lists.newArrayList();
try (Table table = conn.getTable(RSGROUP_TABLE_NAME);

View File

@ -20,11 +20,13 @@ package org.apache.hadoop.hbase.rsgroup;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.NameStringPair;
import org.apache.hadoop.hbase.protobuf.generated.RSGroupProtos;
import org.apache.hadoop.hbase.protobuf.generated.TableProtos;
import org.apache.yetus.audience.InterfaceAudience;
@ -35,14 +37,16 @@ final class RSGroupProtobufUtil {
}
static RSGroupInfo toGroupInfo(RSGroupProtos.RSGroupInfo proto) {
RSGroupInfo RSGroupInfo = new RSGroupInfo(proto.getName());
RSGroupInfo rsGroupInfo = new RSGroupInfo(proto.getName());
for(HBaseProtos.ServerName el: proto.getServersList()) {
RSGroupInfo.addServer(Address.fromParts(el.getHostName(), el.getPort()));
rsGroupInfo.addServer(Address.fromParts(el.getHostName(), el.getPort()));
}
for(TableProtos.TableName pTableName: proto.getTablesList()) {
RSGroupInfo.addTable(ProtobufUtil.toTableName(pTableName));
rsGroupInfo.addTable(ProtobufUtil.toTableName(pTableName));
}
return RSGroupInfo;
proto.getConfigurationList().forEach(pair ->
rsGroupInfo.setConfiguration(pair.getName(), pair.getValue()));
return rsGroupInfo;
}
static RSGroupProtos.RSGroupInfo toProtoGroupInfo(RSGroupInfo pojo) {
@ -57,8 +61,11 @@ final class RSGroupProtobufUtil {
.setPort(el.getPort())
.build());
}
List<NameStringPair> configuration = pojo.getConfiguration().entrySet()
.stream().map(entry -> NameStringPair.newBuilder()
.setName(entry.getKey()).setValue(entry.getValue()).build())
.collect(Collectors.toList());
return RSGroupProtos.RSGroupInfo.newBuilder().setName(pojo.getName())
.addAllServers(hostports)
.addAllTables(tables).build();
.addAllServers(hostports).addAllTables(tables).addAllConfiguration(configuration).build();
}
}

View File

@ -131,6 +131,14 @@ message RenameRSGroupRequest {
message RenameRSGroupResponse {
}
message UpdateRSGroupConfigRequest {
required string group_name = 1;
repeated NameStringPair configuration = 2;
}
message UpdateRSGroupConfigResponse {
}
service RSGroupAdminService {
rpc GetRSGroupInfo(GetRSGroupInfoRequest)
returns (GetRSGroupInfoResponse);
@ -167,4 +175,7 @@ service RSGroupAdminService {
rpc RenameRSGroup(RenameRSGroupRequest)
returns (RenameRSGroupResponse);
rpc UpdateRSGroupConfig(UpdateRSGroupConfigRequest)
returns (UpdateRSGroupConfigResponse);
}

View File

@ -0,0 +1,94 @@
/**
* 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.hadoop.hbase.rsgroup;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.TestName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hbase.thirdparty.com.google.common.collect.Maps;
@Category(MediumTests.class)
public class TestRSGroupConfig extends TestRSGroupsBase {
@ClassRule
public static final HBaseClassTestRule CLASS_RULE =
HBaseClassTestRule.forClass(TestRSGroupConfig.class);
@Rule
public TestName name = new TestName();
protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroupConfig.class);
@BeforeClass
public static void setUpBeforeClass() throws Exception {
TestRSGroupsBase.setUpTestBeforeClass();
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
TestRSGroupsBase.tearDownAfterClass();
}
@Test
public void testSetDefaultGroupConfiguration() throws IOException {
testSetConfiguration(RSGroupInfo.DEFAULT_GROUP);
}
@Test
public void testSetNonDefaultGroupConfiguration() throws IOException {
String group = getGroupName(name.getMethodName());
rsGroupAdmin.addRSGroup(group);
testSetConfiguration(RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.removeRSGroup(group);
}
private void testSetConfiguration(String group) throws IOException {
Map<String, String> configuration = new HashMap<>();
configuration.put("aaa", "111");
configuration.put("bbb", "222");
rsGroupAdmin.updateRSGroupConfig(group, configuration);
RSGroupInfo rsGroup = rsGroupAdmin.getRSGroupInfo(group);
Map<String, String> configFromGroup = Maps.newHashMap(rsGroup.getConfiguration());
assertNotNull(configFromGroup);
assertEquals(2, configFromGroup.size());
assertEquals("111", configFromGroup.get("aaa"));
// unset configuration
rsGroupAdmin.updateRSGroupConfig(group, null);
rsGroup = rsGroupAdmin.getRSGroupInfo(group);
configFromGroup = rsGroup.getConfiguration();
assertNotNull(configFromGroup);
assertEquals(0, configFromGroup.size());
}
}

View File

@ -125,6 +125,13 @@ public class VerifyingRSGroupAdminClient implements RSGroupAdmin {
verify();
}
@Override
public void updateRSGroupConfig(String groupName, Map<String, String> configuration)
throws IOException {
wrapped.updateRSGroupConfig(groupName, configuration);
verify();
}
public void verify() throws IOException {
Map<String, RSGroupInfo> groupMap = Maps.newHashMap();
Set<RSGroupInfo> zList = Sets.newHashSet();

View File

@ -20,6 +20,7 @@ package org.apache.hadoop.hbase.coprocessor;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.hadoop.hbase.ClusterMetrics;
import org.apache.hadoop.hbase.HBaseInterfaceAudience;
@ -1646,4 +1647,22 @@ public interface MasterObserver {
default void postRenameRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final String oldName, final String newName) throws IOException {
}
/**
* Called before update rsgroup config.
* @param ctx the environment to interact with the framework and master
* @param groupName the group name
* @param configuration new configuration of the group name to be set
*/
default void preUpdateRSGroupConfig(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final String groupName, final Map<String, String> configuration) throws IOException {}
/**
* Called after update rsgroup config.
* @param ctx the environment to interact with the framework and master
* @param groupName the group name
* @param configuration new configuration of the group name to be set
*/
default void postUpdateRSGroupConfig(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final String groupName, final Map<String, String> configuration) throws IOException {}
}

View File

@ -22,6 +22,7 @@ import com.google.protobuf.Service;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.ClusterMetrics;
@ -1493,6 +1494,26 @@ public class MasterCoprocessorHost
});
}
public void preUpdateRSGroupConfig(final String groupName,
final Map<String, String> configuration) throws IOException {
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
@Override
protected void call(MasterObserver observer) throws IOException {
observer.preUpdateRSGroupConfig(this, groupName, configuration);
}
});
}
public void postUpdateRSGroupConfig(final String groupName,
final Map<String, String> configuration) throws IOException {
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
@Override
protected void call(MasterObserver observer) throws IOException {
observer.postUpdateRSGroupConfig(this, groupName, configuration);
}
});
}
public void preAddReplicationPeer(final String peerId, final ReplicationPeerConfig peerConfig)
throws IOException {
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {

View File

@ -185,5 +185,42 @@ module Hbase
def rename_rsgroup(oldname, newname)
@admin.renameRSGroup(oldname, newname)
end
#----------------------------------------------------------------------------------------------
# modify a rsgroup configuration
def alter_rsgroup_config(rsgroup_name, *args)
# Fail if table name is not a string
raise(ArgumentError, 'RSGroup name must be of type String') unless rsgroup_name.is_a?(String)
group = @admin.getRSGroupInfo(rsgroup_name)
raise(ArgumentError, 'RSGroup does not exist') unless group
configuration = java.util.HashMap.new
configuration.putAll(group.getConfiguration)
# Flatten params array
args = args.flatten.compact
# Start defining the table
args.each do |arg|
unless arg.is_a?(Hash)
raise(ArgumentError, "#{arg.class} of #{arg.inspect} is not of Hash type")
end
method = arg[METHOD]
if method == 'unset'
configuration.remove(arg[NAME])
elsif method == 'set'
arg.delete(METHOD)
for k, v in arg
v = v.to_s unless v.nil?
configuration.put(k, v)
end
else
raise(ArgumentError, "Unknown method #{method}")
end
end
@admin.updateRSGroupConfig(rsgroup_name, configuration)
end
end
end

View File

@ -508,5 +508,7 @@ Shell.load_command_group(
get_table_rsgroup
remove_servers_rsgroup
rename_rsgroup
alter_rsgroup_config
show_rsgroup_config
]
)

View File

@ -0,0 +1,38 @@
#
#
# 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.
#
module Shell
module Commands
class AlterRsgroupConfig < Command
def help
<<-EOF
Alter RSGroup configuration.
Example:
hbase> alter_rsgroup_config 'grp1', {METHOD => 'set', 'PROPERTY_NAME' => 'PROPERTY_VALUE'}
To delete a property:
hbase> alter_rsgroup_config 'grp1', {METHOD => 'unset', NAME=>'PROPERTY_NAME'}
EOF
end
def command(group, args)
rsgroup_admin.alter_rsgroup_config(group, args)
end
end
end
end

View File

@ -0,0 +1,41 @@
#
#
# 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.
#
module Shell
module Commands
class ShowRsgroupConfig < Command
def help
<<-EOF
Show the configuration of a special RSGroup.
Example:
hbase> show_rsgroup_config 'group'
EOF
end
def command(group)
formatter.header(%w['KEY' 'VALUE'])
config = rsgroup_admin.get_rsgroup(group).getConfiguration
config.each { |key, val|
formatter.row([key, val])
}
formatter.footer(config.size)
end
end
end
end

View File

@ -142,5 +142,19 @@ module Hbase
assert_equal(1, @rsgroup_admin.getRSGroupInfo(new_rs_group_name).getTables.count)
assert_equal(table_name, @rsgroup_admin.getRSGroupInfo(new_rs_group_name).getTables.iterator.next.toString)
end
define_test 'Test alter rsgroup configuration' do
group_name = 'grp1'
@shell.command('add_rsgroup', group_name)
assert_not_nil(@rsgroup_admin.getRSGroupInfo(group_name))
@hbase.rsgroup_admin.alter_rsgroup_config(group_name, {'METHOD' => 'set', 'a' => 'a'})
assert_equal(1, @rsgroup_admin.getRSGroupInfo(group_name).getConfiguration.size)
@hbase.rsgroup_admin.alter_rsgroup_config(group_name, {'METHOD' => 'unset', 'NAME' => 'a'})
assert_equal(0, @rsgroup_admin.getRSGroupInfo(group_name).getConfiguration.size)
@shell.command('remove_rsgroup', group_name)
assert_nil(@rsgroup_admin.getRSGroupInfo(group_name))
end
end
end