001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.rsgroup; 019 020import com.google.protobuf.RpcCallback; 021import com.google.protobuf.RpcController; 022import com.google.protobuf.Service; 023import java.io.IOException; 024import java.util.Collections; 025import java.util.HashSet; 026import java.util.List; 027import java.util.Map; 028import java.util.Optional; 029import java.util.Set; 030import java.util.stream.Collectors; 031import org.apache.hadoop.hbase.CoprocessorEnvironment; 032import org.apache.hadoop.hbase.HBaseIOException; 033import org.apache.hadoop.hbase.HConstants; 034import org.apache.hadoop.hbase.MasterNotRunningException; 035import org.apache.hadoop.hbase.NamespaceDescriptor; 036import org.apache.hadoop.hbase.PleaseHoldException; 037import org.apache.hadoop.hbase.ServerName; 038import org.apache.hadoop.hbase.TableName; 039import org.apache.hadoop.hbase.client.BalanceRequest; 040import org.apache.hadoop.hbase.client.BalanceResponse; 041import org.apache.hadoop.hbase.client.RegionInfo; 042import org.apache.hadoop.hbase.client.SnapshotDescription; 043import org.apache.hadoop.hbase.client.TableDescriptor; 044import org.apache.hadoop.hbase.constraint.ConstraintException; 045import org.apache.hadoop.hbase.coprocessor.CoreCoprocessor; 046import org.apache.hadoop.hbase.coprocessor.HasMasterServices; 047import org.apache.hadoop.hbase.coprocessor.MasterCoprocessor; 048import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment; 049import org.apache.hadoop.hbase.coprocessor.MasterObserver; 050import org.apache.hadoop.hbase.coprocessor.ObserverContext; 051import org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils; 052import org.apache.hadoop.hbase.ipc.RpcServer; 053import org.apache.hadoop.hbase.master.MasterServices; 054import org.apache.hadoop.hbase.net.Address; 055import org.apache.hadoop.hbase.protobuf.ProtobufUtil; 056import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos; 057import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos; 058import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.AddRSGroupRequest; 059import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.AddRSGroupResponse; 060import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.BalanceRSGroupRequest; 061import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.BalanceRSGroupResponse; 062import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoOfServerRequest; 063import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoOfServerResponse; 064import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoOfTableRequest; 065import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoOfTableResponse; 066import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoRequest; 067import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoResponse; 068import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.ListRSGroupInfosRequest; 069import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.ListRSGroupInfosResponse; 070import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.MoveServersAndTablesRequest; 071import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.MoveServersAndTablesResponse; 072import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.MoveServersRequest; 073import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.MoveServersResponse; 074import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.MoveTablesRequest; 075import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.MoveTablesResponse; 076import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RSGroupAdminService; 077import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveRSGroupRequest; 078import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveRSGroupResponse; 079import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveServersRequest; 080import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveServersResponse; 081import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RenameRSGroupRequest; 082import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RenameRSGroupResponse; 083import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.UpdateRSGroupConfigRequest; 084import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.UpdateRSGroupConfigResponse; 085import org.apache.hadoop.hbase.protobuf.generated.TableProtos; 086import org.apache.hadoop.hbase.security.User; 087import org.apache.hadoop.hbase.security.UserProvider; 088import org.apache.hadoop.hbase.security.access.AccessChecker; 089import org.apache.hadoop.hbase.security.access.Permission.Action; 090import org.apache.yetus.audience.InterfaceAudience; 091import org.slf4j.Logger; 092import org.slf4j.LoggerFactory; 093 094import org.apache.hbase.thirdparty.com.google.common.collect.Maps; 095import org.apache.hbase.thirdparty.com.google.common.collect.Sets; 096 097// TODO: Encapsulate MasterObserver functions into separate subclass. 098@CoreCoprocessor 099@InterfaceAudience.Private 100public class RSGroupAdminEndpoint implements MasterCoprocessor, MasterObserver { 101 private static final Logger LOG = LoggerFactory.getLogger(RSGroupAdminEndpoint.class); 102 103 private MasterServices master = null; 104 // Only instance of RSGroupInfoManager. RSGroup aware load balancers ask for this instance on 105 // their setup. 106 private RSGroupInfoManager groupInfoManager; 107 private RSGroupAdminServer groupAdminServer; 108 private final RSGroupAdminService groupAdminService = new RSGroupAdminServiceImpl(); 109 private AccessChecker accessChecker; 110 111 /** Provider for mapping principal names to Users */ 112 private UserProvider userProvider; 113 114 @Override 115 public void start(CoprocessorEnvironment env) throws IOException { 116 if (!(env instanceof HasMasterServices)) { 117 throw new IOException("Does not implement HMasterServices"); 118 } 119 120 master = ((HasMasterServices) env).getMasterServices(); 121 groupInfoManager = RSGroupInfoManagerImpl.getInstance(master); 122 groupAdminServer = new RSGroupAdminServer(master, groupInfoManager); 123 Class<?> clazz = 124 master.getConfiguration().getClass(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, null); 125 if (!RSGroupableBalancer.class.isAssignableFrom(clazz)) { 126 throw new IOException("Configured balancer does not support RegionServer groups."); 127 } 128 accessChecker = ((HasMasterServices) env).getMasterServices().getAccessChecker(); 129 130 // set the user-provider. 131 this.userProvider = UserProvider.instantiate(env.getConfiguration()); 132 } 133 134 @Override 135 public void stop(CoprocessorEnvironment env) { 136 } 137 138 @Override 139 public Iterable<Service> getServices() { 140 return Collections.singleton(groupAdminService); 141 } 142 143 @Override 144 public Optional<MasterObserver> getMasterObserver() { 145 return Optional.of(this); 146 } 147 148 RSGroupInfoManager getGroupInfoManager() { 149 return groupInfoManager; 150 } 151 152 RSGroupAdminServer getGroupAdminServer() { 153 return groupAdminServer; 154 } 155 156 /** 157 * Implementation of RSGroupAdminService defined in RSGroupAdmin.proto. This class calls 158 * {@link RSGroupAdminServer} for actual work, converts result to protocol buffer response, 159 * handles exceptions if any occurred and then calls the {@code RpcCallback} with the response. 160 */ 161 private class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService { 162 @Override 163 public void getRSGroupInfo(RpcController controller, GetRSGroupInfoRequest request, 164 RpcCallback<GetRSGroupInfoResponse> done) { 165 GetRSGroupInfoResponse.Builder builder = GetRSGroupInfoResponse.newBuilder(); 166 String groupName = request.getRSGroupName(); 167 LOG.info( 168 master.getClientIdAuditPrefix() + " initiates rsgroup info retrieval, group=" + groupName); 169 try { 170 checkPermission("getRSGroupInfo"); 171 RSGroupInfo rsGroupInfo = groupAdminServer.getRSGroupInfo(groupName); 172 if (rsGroupInfo != null) { 173 builder.setRSGroupInfo(RSGroupProtobufUtil.toProtoGroupInfo(rsGroupInfo)); 174 } 175 } catch (IOException e) { 176 CoprocessorRpcUtils.setControllerException(controller, e); 177 } 178 done.run(builder.build()); 179 } 180 181 @Override 182 public void getRSGroupInfoOfTable(RpcController controller, 183 GetRSGroupInfoOfTableRequest request, RpcCallback<GetRSGroupInfoOfTableResponse> done) { 184 GetRSGroupInfoOfTableResponse.Builder builder = GetRSGroupInfoOfTableResponse.newBuilder(); 185 TableName tableName = ProtobufUtil.toTableName(request.getTableName()); 186 LOG.info( 187 master.getClientIdAuditPrefix() + " initiates rsgroup info retrieval, table=" + tableName); 188 try { 189 checkPermission("getRSGroupInfoOfTable"); 190 RSGroupInfo RSGroupInfo = groupAdminServer.getRSGroupInfoOfTable(tableName); 191 if (RSGroupInfo != null) { 192 builder.setRSGroupInfo(RSGroupProtobufUtil.toProtoGroupInfo(RSGroupInfo)); 193 } 194 } catch (IOException e) { 195 CoprocessorRpcUtils.setControllerException(controller, e); 196 } 197 done.run(builder.build()); 198 } 199 200 @Override 201 public void moveServers(RpcController controller, MoveServersRequest request, 202 RpcCallback<MoveServersResponse> done) { 203 MoveServersResponse.Builder builder = MoveServersResponse.newBuilder(); 204 Set<Address> hostPorts = Sets.newHashSet(); 205 for (HBaseProtos.ServerName el : request.getServersList()) { 206 hostPorts.add(Address.fromParts(el.getHostName(), el.getPort())); 207 } 208 LOG.info(master.getClientIdAuditPrefix() + " move servers " + hostPorts + " to rsgroup " 209 + request.getTargetGroup()); 210 try { 211 if (master.getMasterCoprocessorHost() != null) { 212 master.getMasterCoprocessorHost().preMoveServers(hostPorts, request.getTargetGroup()); 213 } 214 checkPermission("moveServers"); 215 groupAdminServer.moveServers(hostPorts, request.getTargetGroup()); 216 if (master.getMasterCoprocessorHost() != null) { 217 master.getMasterCoprocessorHost().postMoveServers(hostPorts, request.getTargetGroup()); 218 } 219 } catch (IOException e) { 220 CoprocessorRpcUtils.setControllerException(controller, e); 221 } 222 done.run(builder.build()); 223 } 224 225 @Override 226 public void moveTables(RpcController controller, MoveTablesRequest request, 227 RpcCallback<MoveTablesResponse> done) { 228 MoveTablesResponse.Builder builder = MoveTablesResponse.newBuilder(); 229 Set<TableName> tables = new HashSet<>(request.getTableNameList().size()); 230 for (TableProtos.TableName tableName : request.getTableNameList()) { 231 tables.add(ProtobufUtil.toTableName(tableName)); 232 } 233 LOG.info(master.getClientIdAuditPrefix() + " move tables " + tables + " to rsgroup " 234 + request.getTargetGroup()); 235 try { 236 if (master.getMasterCoprocessorHost() != null) { 237 master.getMasterCoprocessorHost().preMoveTables(tables, request.getTargetGroup()); 238 } 239 checkPermission("moveTables"); 240 groupAdminServer.moveTables(tables, request.getTargetGroup()); 241 if (master.getMasterCoprocessorHost() != null) { 242 master.getMasterCoprocessorHost().postMoveTables(tables, request.getTargetGroup()); 243 } 244 } catch (IOException e) { 245 CoprocessorRpcUtils.setControllerException(controller, e); 246 } 247 done.run(builder.build()); 248 } 249 250 @Override 251 public void addRSGroup(RpcController controller, AddRSGroupRequest request, 252 RpcCallback<AddRSGroupResponse> done) { 253 AddRSGroupResponse.Builder builder = AddRSGroupResponse.newBuilder(); 254 LOG.info(master.getClientIdAuditPrefix() + " add rsgroup " + request.getRSGroupName()); 255 try { 256 if (master.getMasterCoprocessorHost() != null) { 257 master.getMasterCoprocessorHost().preAddRSGroup(request.getRSGroupName()); 258 } 259 checkPermission("addRSGroup"); 260 groupAdminServer.addRSGroup(request.getRSGroupName()); 261 if (master.getMasterCoprocessorHost() != null) { 262 master.getMasterCoprocessorHost().postAddRSGroup(request.getRSGroupName()); 263 } 264 } catch (IOException e) { 265 CoprocessorRpcUtils.setControllerException(controller, e); 266 } 267 done.run(builder.build()); 268 } 269 270 @Override 271 public void removeRSGroup(RpcController controller, RemoveRSGroupRequest request, 272 RpcCallback<RemoveRSGroupResponse> done) { 273 RemoveRSGroupResponse.Builder builder = RemoveRSGroupResponse.newBuilder(); 274 LOG.info(master.getClientIdAuditPrefix() + " remove rsgroup " + request.getRSGroupName()); 275 try { 276 if (master.getMasterCoprocessorHost() != null) { 277 master.getMasterCoprocessorHost().preRemoveRSGroup(request.getRSGroupName()); 278 } 279 checkPermission("removeRSGroup"); 280 groupAdminServer.removeRSGroup(request.getRSGroupName()); 281 if (master.getMasterCoprocessorHost() != null) { 282 master.getMasterCoprocessorHost().postRemoveRSGroup(request.getRSGroupName()); 283 } 284 } catch (IOException e) { 285 CoprocessorRpcUtils.setControllerException(controller, e); 286 } 287 done.run(builder.build()); 288 } 289 290 @Override 291 public void balanceRSGroup(RpcController controller, BalanceRSGroupRequest request, 292 RpcCallback<BalanceRSGroupResponse> done) { 293 BalanceRequest balanceRequest = RSGroupProtobufUtil.toBalanceRequest(request); 294 295 BalanceRSGroupResponse.Builder builder = 296 BalanceRSGroupResponse.newBuilder().setBalanceRan(false); 297 298 LOG.info( 299 master.getClientIdAuditPrefix() + " balance rsgroup, group=" + request.getRSGroupName()); 300 try { 301 if (master.getMasterCoprocessorHost() != null) { 302 master.getMasterCoprocessorHost().preBalanceRSGroup(request.getRSGroupName(), 303 balanceRequest); 304 } 305 306 checkPermission("balanceRSGroup"); 307 BalanceResponse response = 308 groupAdminServer.balanceRSGroup(request.getRSGroupName(), balanceRequest); 309 RSGroupProtobufUtil.populateBalanceRSGroupResponse(builder, response); 310 311 if (master.getMasterCoprocessorHost() != null) { 312 master.getMasterCoprocessorHost().postBalanceRSGroup(request.getRSGroupName(), 313 balanceRequest, response); 314 } 315 } catch (IOException e) { 316 CoprocessorRpcUtils.setControllerException(controller, e); 317 } 318 319 done.run(builder.build()); 320 } 321 322 @Override 323 public void listRSGroupInfos(RpcController controller, ListRSGroupInfosRequest request, 324 RpcCallback<ListRSGroupInfosResponse> done) { 325 ListRSGroupInfosResponse.Builder builder = ListRSGroupInfosResponse.newBuilder(); 326 LOG.info(master.getClientIdAuditPrefix() + " list rsgroup"); 327 try { 328 checkPermission("listRSGroup"); 329 for (RSGroupInfo RSGroupInfo : groupAdminServer.listRSGroups()) { 330 builder.addRSGroupInfo(RSGroupProtobufUtil.toProtoGroupInfo(RSGroupInfo)); 331 } 332 } catch (IOException e) { 333 CoprocessorRpcUtils.setControllerException(controller, e); 334 } 335 done.run(builder.build()); 336 } 337 338 @Override 339 public void getRSGroupInfoOfServer(RpcController controller, 340 GetRSGroupInfoOfServerRequest request, RpcCallback<GetRSGroupInfoOfServerResponse> done) { 341 GetRSGroupInfoOfServerResponse.Builder builder = GetRSGroupInfoOfServerResponse.newBuilder(); 342 Address hp = 343 Address.fromParts(request.getServer().getHostName(), request.getServer().getPort()); 344 LOG.info(master.getClientIdAuditPrefix() + " initiates rsgroup info retrieval, server=" + hp); 345 try { 346 checkPermission("getRSGroupInfoOfServer"); 347 RSGroupInfo info = groupAdminServer.getRSGroupOfServer(hp); 348 if (info != null) { 349 builder.setRSGroupInfo(RSGroupProtobufUtil.toProtoGroupInfo(info)); 350 } 351 } catch (IOException e) { 352 CoprocessorRpcUtils.setControllerException(controller, e); 353 } 354 done.run(builder.build()); 355 } 356 357 @Override 358 public void moveServersAndTables(RpcController controller, MoveServersAndTablesRequest request, 359 RpcCallback<MoveServersAndTablesResponse> done) { 360 MoveServersAndTablesResponse.Builder builder = MoveServersAndTablesResponse.newBuilder(); 361 Set<Address> hostPorts = Sets.newHashSet(); 362 for (HBaseProtos.ServerName el : request.getServersList()) { 363 hostPorts.add(Address.fromParts(el.getHostName(), el.getPort())); 364 } 365 Set<TableName> tables = new HashSet<>(request.getTableNameList().size()); 366 for (TableProtos.TableName tableName : request.getTableNameList()) { 367 tables.add(ProtobufUtil.toTableName(tableName)); 368 } 369 LOG.info(master.getClientIdAuditPrefix() + " move servers " + hostPorts + " and tables " 370 + tables + " to rsgroup" + request.getTargetGroup()); 371 try { 372 if (master.getMasterCoprocessorHost() != null) { 373 master.getMasterCoprocessorHost().preMoveServersAndTables(hostPorts, tables, 374 request.getTargetGroup()); 375 } 376 checkPermission("moveServersAndTables"); 377 groupAdminServer.moveServersAndTables(hostPorts, tables, request.getTargetGroup()); 378 if (master.getMasterCoprocessorHost() != null) { 379 master.getMasterCoprocessorHost().postMoveServersAndTables(hostPorts, tables, 380 request.getTargetGroup()); 381 } 382 } catch (IOException e) { 383 CoprocessorRpcUtils.setControllerException(controller, e); 384 } 385 done.run(builder.build()); 386 } 387 388 @Override 389 public void removeServers(RpcController controller, RemoveServersRequest request, 390 RpcCallback<RemoveServersResponse> done) { 391 RemoveServersResponse.Builder builder = RemoveServersResponse.newBuilder(); 392 Set<Address> servers = Sets.newHashSet(); 393 for (HBaseProtos.ServerName el : request.getServersList()) { 394 servers.add(Address.fromParts(el.getHostName(), el.getPort())); 395 } 396 LOG.info(master.getClientIdAuditPrefix() + " remove decommissioned servers from rsgroup: " 397 + servers); 398 try { 399 if (master.getMasterCoprocessorHost() != null) { 400 master.getMasterCoprocessorHost().preRemoveServers(servers); 401 } 402 checkPermission("removeServers"); 403 groupAdminServer.removeServers(servers); 404 if (master.getMasterCoprocessorHost() != null) { 405 master.getMasterCoprocessorHost().postRemoveServers(servers); 406 } 407 } catch (IOException e) { 408 CoprocessorRpcUtils.setControllerException(controller, e); 409 } 410 done.run(builder.build()); 411 } 412 413 @Override 414 public void renameRSGroup(RpcController controller, RenameRSGroupRequest request, 415 RpcCallback<RenameRSGroupResponse> done) { 416 String oldRSGroup = request.getOldRsgroupName(); 417 String newRSGroup = request.getNewRsgroupName(); 418 LOG.info("{} rename rsgroup from {} to {}", master.getClientIdAuditPrefix(), oldRSGroup, 419 newRSGroup); 420 421 RenameRSGroupResponse.Builder builder = RenameRSGroupResponse.newBuilder(); 422 try { 423 if (master.getMasterCoprocessorHost() != null) { 424 master.getMasterCoprocessorHost().preRenameRSGroup(oldRSGroup, newRSGroup); 425 } 426 checkPermission("renameRSGroup"); 427 groupAdminServer.renameRSGroup(oldRSGroup, newRSGroup); 428 if (master.getMasterCoprocessorHost() != null) { 429 master.getMasterCoprocessorHost().postRenameRSGroup(oldRSGroup, newRSGroup); 430 } 431 } catch (IOException e) { 432 CoprocessorRpcUtils.setControllerException(controller, e); 433 } 434 done.run(builder.build()); 435 } 436 437 @Override 438 public void updateRSGroupConfig(RpcController controller, UpdateRSGroupConfigRequest request, 439 RpcCallback<UpdateRSGroupConfigResponse> done) { 440 UpdateRSGroupConfigResponse.Builder builder = UpdateRSGroupConfigResponse.newBuilder(); 441 String groupName = request.getGroupName(); 442 Map<String, String> configuration = Maps.newHashMap(); 443 request.getConfigurationList().forEach(p -> configuration.put(p.getName(), p.getValue())); 444 LOG.info("{} update rsgroup {} configuration {}", master.getClientIdAuditPrefix(), groupName, 445 configuration); 446 try { 447 if (master.getMasterCoprocessorHost() != null) { 448 master.getMasterCoprocessorHost().preUpdateRSGroupConfig(groupName, configuration); 449 } 450 groupAdminServer.updateRSGroupConfig(groupName, configuration); 451 if (master.getMasterCoprocessorHost() != null) { 452 master.getMasterCoprocessorHost().postUpdateRSGroupConfig(groupName, configuration); 453 } 454 } catch (IOException e) { 455 CoprocessorRpcUtils.setControllerException(controller, e); 456 } 457 done.run(builder.build()); 458 } 459 } 460 461 boolean rsgroupHasServersOnline(TableDescriptor desc) throws IOException { 462 String groupName; 463 try { 464 groupName = master.getClusterSchema().getNamespace(desc.getTableName().getNamespaceAsString()) 465 .getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP); 466 if (groupName == null) { 467 groupName = RSGroupInfo.DEFAULT_GROUP; 468 } 469 } catch (MasterNotRunningException | PleaseHoldException e) { 470 LOG.info("Master has not initialized yet; temporarily using default RSGroup '" 471 + RSGroupInfo.DEFAULT_GROUP + "' for deploy of system table"); 472 groupName = RSGroupInfo.DEFAULT_GROUP; 473 } 474 475 RSGroupInfo rsGroupInfo = groupAdminServer.getRSGroupInfo(groupName); 476 if (rsGroupInfo == null) { 477 throw new ConstraintException( 478 "Default RSGroup (" + groupName + ") for this table's " + "namespace does not exist."); 479 } 480 481 for (ServerName onlineServer : master.getServerManager().createDestinationServersList()) { 482 if (rsGroupInfo.getServers().contains(onlineServer.getAddress())) { 483 return true; 484 } 485 } 486 return false; 487 } 488 489 void assignTableToGroup(TableDescriptor desc) throws IOException { 490 RSGroupInfo rsGroupInfo = determineRSGroupInfoForTable(desc); 491 if (rsGroupInfo == null) { 492 throw new ConstraintException( 493 "Default RSGroup for this table " + desc.getTableName() + " does not exist."); 494 } 495 if (!rsGroupInfo.containsTable(desc.getTableName())) { 496 LOG.debug("Pre-moving table " + desc.getTableName() + " to RSGroup " + rsGroupInfo.getName()); 497 groupAdminServer.moveTables(Sets.newHashSet(desc.getTableName()), rsGroupInfo.getName()); 498 } 499 } 500 501 ///////////////////////////////////////////////////////////////////////////// 502 // MasterObserver overrides 503 ///////////////////////////////////////////////////////////////////////////// 504 505 @Override 506 public void preCreateTableAction(final ObserverContext<MasterCoprocessorEnvironment> ctx, 507 final TableDescriptor desc, final RegionInfo[] regions) throws IOException { 508 if (desc.getTableName().isSystemTable()) { 509 return; 510 } 511 moveTableToValidRSGroup(desc); 512 } 513 514 @Override 515 public void preModifyTableAction(ObserverContext<MasterCoprocessorEnvironment> ctx, 516 TableName tableName, TableDescriptor currentDescriptor, TableDescriptor newDescriptor) 517 throws IOException { 518 // If table's rsgroup is changed, it must be valid 519 if (!currentDescriptor.getRegionServerGroup().equals(newDescriptor.getRegionServerGroup())) { 520 RSGroupInfo rsGroupInfo = determineRSGroupInfoForTable(newDescriptor); 521 validateRSGroup(newDescriptor, rsGroupInfo); 522 } 523 } 524 525 @Override 526 public void postCompletedModifyTableAction(ObserverContext<MasterCoprocessorEnvironment> ctx, 527 TableName tableName, TableDescriptor oldDescriptor, TableDescriptor currentDescriptor) 528 throws IOException { 529 // If table's rsgroup is changed, move table into the rsgroup. 530 if (!oldDescriptor.getRegionServerGroup().equals(currentDescriptor.getRegionServerGroup())) { 531 RSGroupInfo rsGroupInfo = determineRSGroupInfoForTable(currentDescriptor); 532 moveTableToRSGroup(currentDescriptor, rsGroupInfo); 533 } 534 } 535 536 // Determine and validate rs group then move table to this valid rs group. 537 private void moveTableToValidRSGroup(TableDescriptor desc) throws IOException { 538 RSGroupInfo rsGroupInfo = determineRSGroupInfoForTable(desc); 539 validateRSGroup(desc, rsGroupInfo); 540 moveTableToRSGroup(desc, rsGroupInfo); 541 } 542 543 private void validateRSGroup(TableDescriptor desc, RSGroupInfo rsGroupInfo) throws IOException { 544 if (rsGroupInfo == null) { 545 throw new ConstraintException( 546 "Default RSGroup for this table " + desc.getTableName() + " does not exist."); 547 } 548 if (!RSGroupUtil.rsGroupHasOnlineServer(master, rsGroupInfo)) { 549 throw new HBaseIOException("No online servers in the rsgroup " + rsGroupInfo.getName() 550 + " which table " + desc.getTableName().getNameAsString() + " belongs to"); 551 } 552 } 553 554 private void moveTableToRSGroup(final TableDescriptor desc, RSGroupInfo rsGroupInfo) 555 throws IOException { 556 // In case of modify table, when rs group is not changed, move is not required. 557 if (!rsGroupInfo.containsTable(desc.getTableName())) { 558 synchronized (groupInfoManager) { 559 groupInfoManager.moveTables(Collections.singleton(desc.getTableName()), 560 rsGroupInfo.getName()); 561 } 562 } 563 } 564 565 private RSGroupInfo determineRSGroupInfoForTable(final TableDescriptor desc) throws IOException { 566 Optional<String> optGroupNameOfTable = desc.getRegionServerGroup(); 567 if (optGroupNameOfTable.isPresent()) { 568 final RSGroupInfo rsGroup = groupInfoManager.getRSGroup(optGroupNameOfTable.get()); 569 if (rsGroup == null) { 570 // When rs group is set in table descriptor then it must exist 571 throw new ConstraintException( 572 "Region server group " + optGroupNameOfTable.get() + " does not exist."); 573 } else { 574 return rsGroup; 575 } 576 } 577 return groupInfoManager.determineRSGroupInfoForTable(desc.getTableName()); 578 } 579 580 // Remove table from its RSGroup. 581 @Override 582 public void postDeleteTable(ObserverContext<MasterCoprocessorEnvironment> ctx, 583 TableName tableName) throws IOException { 584 try { 585 RSGroupInfo group = groupAdminServer.getRSGroupInfoOfTable(tableName); 586 if (group != null) { 587 LOG.debug(String.format("Removing deleted table '%s' from rsgroup '%s'", tableName, 588 group.getName())); 589 groupAdminServer.moveTables(Sets.newHashSet(tableName), null); 590 } 591 } catch (IOException ex) { 592 LOG.debug("Failed to perform RSGroup information cleanup for table: " + tableName, ex); 593 } 594 } 595 596 @Override 597 public void preCreateNamespace(ObserverContext<MasterCoprocessorEnvironment> ctx, 598 NamespaceDescriptor ns) throws IOException { 599 String group = ns.getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP); 600 if (group != null && groupAdminServer.getRSGroupInfo(group) == null) { 601 throw new ConstraintException("Region server group " + group + " does not exist."); 602 } 603 } 604 605 @Override 606 public void preModifyNamespace(ObserverContext<MasterCoprocessorEnvironment> ctx, 607 NamespaceDescriptor ns) throws IOException { 608 preCreateNamespace(ctx, ns); 609 } 610 611 @Override 612 public void preCloneSnapshot(ObserverContext<MasterCoprocessorEnvironment> ctx, 613 SnapshotDescription snapshot, TableDescriptor desc) throws IOException { 614 assignTableToGroup(desc); 615 } 616 617 @Override 618 public void postClearDeadServers(ObserverContext<MasterCoprocessorEnvironment> ctx, 619 List<ServerName> servers, List<ServerName> notClearedServers) throws IOException { 620 Set<Address> clearedServer = 621 servers.stream().filter(server -> !notClearedServers.contains(server)) 622 .map(ServerName::getAddress).collect(Collectors.toSet()); 623 if (!clearedServer.isEmpty()) { 624 groupAdminServer.removeServers(clearedServer); 625 } 626 } 627 628 public void checkPermission(String request) throws IOException { 629 accessChecker.requirePermission(getActiveUser(), request, null, Action.ADMIN); 630 } 631 632 /** 633 * Returns the active user to which authorization checks should be applied. If we are in the 634 * context of an RPC call, the remote user is used, otherwise the currently logged in user is 635 * used. 636 */ 637 private User getActiveUser() throws IOException { 638 // for non-rpc handling, fallback to system user 639 Optional<User> optionalUser = RpcServer.getRequestUser(); 640 if (optionalUser.isPresent()) { 641 return optionalUser.get(); 642 } 643 return userProvider.getCurrent(); 644 } 645}