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 */
018
019package org.apache.hadoop.hbase.rsgroup;
020
021import com.google.protobuf.RpcCallback;
022import com.google.protobuf.RpcController;
023import com.google.protobuf.Service;
024
025import java.io.IOException;
026import java.util.Collections;
027import java.util.HashSet;
028import java.util.List;
029import java.util.Map;
030import java.util.Optional;
031import java.util.Set;
032import java.util.stream.Collectors;
033
034import org.apache.hadoop.hbase.CoprocessorEnvironment;
035import org.apache.hadoop.hbase.HBaseIOException;
036import org.apache.hadoop.hbase.HConstants;
037import org.apache.hadoop.hbase.MasterNotRunningException;
038import org.apache.hadoop.hbase.NamespaceDescriptor;
039import org.apache.hadoop.hbase.PleaseHoldException;
040import org.apache.hadoop.hbase.ServerName;
041import org.apache.hadoop.hbase.TableName;
042import org.apache.hadoop.hbase.client.RegionInfo;
043import org.apache.hadoop.hbase.client.SnapshotDescription;
044import org.apache.hadoop.hbase.client.TableDescriptor;
045import org.apache.hadoop.hbase.constraint.ConstraintException;
046import org.apache.hadoop.hbase.coprocessor.CoreCoprocessor;
047import org.apache.hadoop.hbase.coprocessor.HasMasterServices;
048import org.apache.hadoop.hbase.coprocessor.MasterCoprocessor;
049import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
050import org.apache.hadoop.hbase.coprocessor.MasterObserver;
051import org.apache.hadoop.hbase.coprocessor.ObserverContext;
052import org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils;
053import org.apache.hadoop.hbase.ipc.RpcServer;
054import org.apache.hadoop.hbase.master.MasterServices;
055import org.apache.hadoop.hbase.net.Address;
056import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
057import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
058import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos;
059import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.AddRSGroupRequest;
060import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.AddRSGroupResponse;
061import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.BalanceRSGroupRequest;
062import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.BalanceRSGroupResponse;
063import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoOfServerRequest;
064import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoOfServerResponse;
065import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoOfTableRequest;
066import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoOfTableResponse;
067import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoRequest;
068import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoResponse;
069import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.ListRSGroupInfosRequest;
070import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.ListRSGroupInfosResponse;
071import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.MoveServersAndTablesRequest;
072import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.MoveServersAndTablesResponse;
073import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.MoveServersRequest;
074import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.MoveServersResponse;
075import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.MoveTablesRequest;
076import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.MoveTablesResponse;
077import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RSGroupAdminService;
078import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveRSGroupRequest;
079import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveRSGroupResponse;
080import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveServersRequest;
081import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveServersResponse;
082import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RenameRSGroupRequest;
083import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RenameRSGroupResponse;
084import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.UpdateRSGroupConfigRequest;
085import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.UpdateRSGroupConfigResponse;
086import org.apache.hadoop.hbase.protobuf.generated.TableProtos;
087import org.apache.hadoop.hbase.security.User;
088import org.apache.hadoop.hbase.security.UserProvider;
089import org.apache.hadoop.hbase.security.access.AccessChecker;
090import org.apache.hadoop.hbase.security.access.Permission.Action;
091import org.apache.hbase.thirdparty.com.google.common.collect.Maps;
092import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
093import org.apache.yetus.audience.InterfaceAudience;
094import org.slf4j.Logger;
095import org.slf4j.LoggerFactory;
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   * Implementation of RSGroupAdminService defined in RSGroupAdmin.proto.
157   * This class calls {@link RSGroupAdminServer} for actual work, converts result to protocol
158   * buffer response, handles exceptions if any occurred and then calls the {@code RpcCallback} with
159   * the response.
160   */
161  private class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
162    @Override
163    public void getRSGroupInfo(RpcController controller,
164        GetRSGroupInfoRequest request, RpcCallback<GetRSGroupInfoResponse> done) {
165      GetRSGroupInfoResponse.Builder builder = GetRSGroupInfoResponse.newBuilder();
166      String groupName = request.getRSGroupName();
167      LOG.info(master.getClientIdAuditPrefix() + " initiates rsgroup info retrieval, group="
168              + 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(master.getClientIdAuditPrefix() + " initiates rsgroup info retrieval, table="
187          + 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,
272        RemoveRSGroupRequest request, RpcCallback<RemoveRSGroupResponse> done) {
273      RemoveRSGroupResponse.Builder builder =
274          RemoveRSGroupResponse.newBuilder();
275      LOG.info(master.getClientIdAuditPrefix() + " remove rsgroup " + request.getRSGroupName());
276      try {
277        if (master.getMasterCoprocessorHost() != null) {
278          master.getMasterCoprocessorHost().preRemoveRSGroup(request.getRSGroupName());
279        }
280        checkPermission("removeRSGroup");
281        groupAdminServer.removeRSGroup(request.getRSGroupName());
282        if (master.getMasterCoprocessorHost() != null) {
283          master.getMasterCoprocessorHost().postRemoveRSGroup(request.getRSGroupName());
284        }
285      } catch (IOException e) {
286        CoprocessorRpcUtils.setControllerException(controller, e);
287      }
288      done.run(builder.build());
289    }
290
291    @Override
292    public void balanceRSGroup(RpcController controller,
293        BalanceRSGroupRequest request, RpcCallback<BalanceRSGroupResponse> done) {
294      BalanceRSGroupResponse.Builder builder = BalanceRSGroupResponse.newBuilder();
295      LOG.info(master.getClientIdAuditPrefix() + " balance rsgroup, group="
296          + request.getRSGroupName());
297      try {
298        if (master.getMasterCoprocessorHost() != null) {
299          master.getMasterCoprocessorHost().preBalanceRSGroup(request.getRSGroupName());
300        }
301        checkPermission("balanceRSGroup");
302        boolean balancerRan = groupAdminServer.balanceRSGroup(request.getRSGroupName());
303        builder.setBalanceRan(balancerRan);
304        if (master.getMasterCoprocessorHost() != null) {
305          master.getMasterCoprocessorHost().postBalanceRSGroup(request.getRSGroupName(),
306              balancerRan);
307        }
308      } catch (IOException e) {
309        CoprocessorRpcUtils.setControllerException(controller, e);
310        builder.setBalanceRan(false);
311      }
312      done.run(builder.build());
313    }
314
315    @Override
316    public void listRSGroupInfos(RpcController controller,
317        ListRSGroupInfosRequest request, RpcCallback<ListRSGroupInfosResponse> done) {
318      ListRSGroupInfosResponse.Builder builder = ListRSGroupInfosResponse.newBuilder();
319      LOG.info(master.getClientIdAuditPrefix() + " list rsgroup");
320      try {
321        checkPermission("listRSGroup");
322        for (RSGroupInfo RSGroupInfo : groupAdminServer.listRSGroups()) {
323          builder.addRSGroupInfo(RSGroupProtobufUtil.toProtoGroupInfo(RSGroupInfo));
324        }
325      } catch (IOException e) {
326        CoprocessorRpcUtils.setControllerException(controller, e);
327      }
328      done.run(builder.build());
329    }
330
331    @Override
332    public void getRSGroupInfoOfServer(RpcController controller,
333        GetRSGroupInfoOfServerRequest request, RpcCallback<GetRSGroupInfoOfServerResponse> done) {
334      GetRSGroupInfoOfServerResponse.Builder builder = GetRSGroupInfoOfServerResponse.newBuilder();
335      Address hp = Address.fromParts(request.getServer().getHostName(),
336          request.getServer().getPort());
337      LOG.info(master.getClientIdAuditPrefix() + " initiates rsgroup info retrieval, server="
338          + hp);
339      try {
340        checkPermission("getRSGroupInfoOfServer");
341        RSGroupInfo info = groupAdminServer.getRSGroupOfServer(hp);
342        if (info != null) {
343          builder.setRSGroupInfo(RSGroupProtobufUtil.toProtoGroupInfo(info));
344        }
345      } catch (IOException e) {
346        CoprocessorRpcUtils.setControllerException(controller, e);
347      }
348      done.run(builder.build());
349    }
350
351    @Override
352    public void moveServersAndTables(RpcController controller,
353        MoveServersAndTablesRequest request, RpcCallback<MoveServersAndTablesResponse> done) {
354      MoveServersAndTablesResponse.Builder builder = MoveServersAndTablesResponse.newBuilder();
355      Set<Address> hostPorts = Sets.newHashSet();
356      for (HBaseProtos.ServerName el : request.getServersList()) {
357        hostPorts.add(Address.fromParts(el.getHostName(), el.getPort()));
358      }
359      Set<TableName> tables = new HashSet<>(request.getTableNameList().size());
360      for (TableProtos.TableName tableName : request.getTableNameList()) {
361        tables.add(ProtobufUtil.toTableName(tableName));
362      }
363      LOG.info(master.getClientIdAuditPrefix() + " move servers " + hostPorts
364          + " and tables " + tables + " to rsgroup" + request.getTargetGroup());
365      try {
366        if (master.getMasterCoprocessorHost() != null) {
367          master.getMasterCoprocessorHost().preMoveServersAndTables(hostPorts, tables,
368              request.getTargetGroup());
369        }
370        checkPermission("moveServersAndTables");
371        groupAdminServer.moveServersAndTables(hostPorts, tables, request.getTargetGroup());
372        if (master.getMasterCoprocessorHost() != null) {
373          master.getMasterCoprocessorHost().postMoveServersAndTables(hostPorts, tables,
374              request.getTargetGroup());
375        }
376      } catch (IOException e) {
377        CoprocessorRpcUtils.setControllerException(controller, e);
378      }
379      done.run(builder.build());
380    }
381
382    @Override
383    public void removeServers(RpcController controller,
384        RemoveServersRequest request,
385        RpcCallback<RemoveServersResponse> done) {
386      RemoveServersResponse.Builder builder =
387          RemoveServersResponse.newBuilder();
388      Set<Address> servers = Sets.newHashSet();
389      for (HBaseProtos.ServerName el : request.getServersList()) {
390        servers.add(Address.fromParts(el.getHostName(), el.getPort()));
391      }
392      LOG.info(master.getClientIdAuditPrefix()
393          + " remove decommissioned servers from rsgroup: " + servers);
394      try {
395        if (master.getMasterCoprocessorHost() != null) {
396          master.getMasterCoprocessorHost().preRemoveServers(servers);
397        }
398        checkPermission("removeServers");
399        groupAdminServer.removeServers(servers);
400        if (master.getMasterCoprocessorHost() != null) {
401          master.getMasterCoprocessorHost().postRemoveServers(servers);
402        }
403      } catch (IOException e) {
404        CoprocessorRpcUtils.setControllerException(controller, e);
405      }
406      done.run(builder.build());
407    }
408
409    @Override
410    public void renameRSGroup(RpcController controller,
411                              RenameRSGroupRequest request,
412                              RpcCallback<RenameRSGroupResponse> done) {
413      String oldRSGroup = request.getOldRsgroupName();
414      String newRSGroup = request.getNewRsgroupName();
415      LOG.info("{} rename rsgroup from {} to {}",
416        master.getClientIdAuditPrefix(), oldRSGroup, newRSGroup);
417
418      RenameRSGroupResponse.Builder builder = RenameRSGroupResponse.newBuilder();
419      try {
420        if (master.getMasterCoprocessorHost() != null) {
421          master.getMasterCoprocessorHost().preRenameRSGroup(oldRSGroup, newRSGroup);
422        }
423        checkPermission("renameRSGroup");
424        groupAdminServer.renameRSGroup(oldRSGroup, newRSGroup);
425        if (master.getMasterCoprocessorHost() != null) {
426          master.getMasterCoprocessorHost().postRenameRSGroup(oldRSGroup, newRSGroup);
427        }
428      } catch (IOException e) {
429        CoprocessorRpcUtils.setControllerException(controller, e);
430      }
431      done.run(builder.build());
432    }
433
434    @Override
435    public void updateRSGroupConfig(RpcController controller, UpdateRSGroupConfigRequest request,
436                                    RpcCallback<UpdateRSGroupConfigResponse> done) {
437      UpdateRSGroupConfigResponse.Builder builder = UpdateRSGroupConfigResponse.newBuilder();
438      String groupName = request.getGroupName();
439      Map<String, String> configuration = Maps.newHashMap();
440      request.getConfigurationList().forEach(p -> configuration.put(p.getName(), p.getValue()));
441      LOG.info("{} update rsgroup {} configuration {}", master.getClientIdAuditPrefix(), groupName,
442          configuration);
443      try {
444        if (master.getMasterCoprocessorHost() != null) {
445          master.getMasterCoprocessorHost().preUpdateRSGroupConfig(groupName, configuration);
446        }
447        groupAdminServer.updateRSGroupConfig(groupName, configuration);
448        if (master.getMasterCoprocessorHost() != null) {
449          master.getMasterCoprocessorHost().postUpdateRSGroupConfig(groupName, configuration);
450        }
451      } catch (IOException e) {
452        CoprocessorRpcUtils.setControllerException(controller, e);
453      }
454      done.run(builder.build());
455    }
456  }
457
458  boolean rsgroupHasServersOnline(TableDescriptor desc) throws IOException {
459    String groupName;
460    try {
461      groupName =
462        master.getClusterSchema().getNamespace(desc.getTableName().getNamespaceAsString())
463        .getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP);
464      if (groupName == null) {
465        groupName = RSGroupInfo.DEFAULT_GROUP;
466      }
467    } catch (MasterNotRunningException | PleaseHoldException e) {
468      LOG.info("Master has not initialized yet; temporarily using default RSGroup '" +
469          RSGroupInfo.DEFAULT_GROUP + "' for deploy of system table");
470      groupName = RSGroupInfo.DEFAULT_GROUP;
471    }
472
473    RSGroupInfo rsGroupInfo = groupAdminServer.getRSGroupInfo(groupName);
474    if (rsGroupInfo == null) {
475      throw new ConstraintException(
476          "Default RSGroup (" + groupName + ") for this table's " + "namespace does not exist.");
477    }
478
479    for (ServerName onlineServer : master.getServerManager().createDestinationServersList()) {
480      if (rsGroupInfo.getServers().contains(onlineServer.getAddress())) {
481        return true;
482      }
483    }
484    return false;
485  }
486
487  void assignTableToGroup(TableDescriptor desc) throws IOException {
488    RSGroupInfo rsGroupInfo = groupInfoManager.determineRSGroupInfoForTable(desc.getTableName());
489    if (rsGroupInfo == null) {
490      throw new ConstraintException("Default RSGroup for this table " + desc.getTableName()
491        + " does not exist.");
492    }
493    if (!rsGroupInfo.containsTable(desc.getTableName())) {
494      LOG.debug("Pre-moving table " + desc.getTableName() + " to RSGroup " + rsGroupInfo.getName());
495      groupAdminServer.moveTables(Sets.newHashSet(desc.getTableName()), rsGroupInfo.getName());
496    }
497  }
498
499  /////////////////////////////////////////////////////////////////////////////
500  // MasterObserver overrides
501  /////////////////////////////////////////////////////////////////////////////
502
503  @Override
504  public void preCreateTableAction(
505      final ObserverContext<MasterCoprocessorEnvironment> ctx,
506      final TableDescriptor desc,
507      final RegionInfo[] regions) throws IOException {
508    if (desc.getTableName().isSystemTable()) {
509      return;
510    }
511    RSGroupInfo rsGroupInfo = groupInfoManager.determineRSGroupInfoForTable(desc.getTableName());
512    if (rsGroupInfo == null) {
513      throw new ConstraintException("Default RSGroup for this table " + desc.getTableName()
514        + " does not exist.");
515    }
516    if (!RSGroupUtil.rsGroupHasOnlineServer(master, rsGroupInfo)) {
517      throw new HBaseIOException("No online servers in the rsgroup " + rsGroupInfo.getName()
518        + " which table " + desc.getTableName().getNameAsString() + " belongs to");
519    }
520    synchronized (groupInfoManager) {
521      groupInfoManager.moveTables(
522        Collections.singleton(desc.getTableName()), rsGroupInfo.getName());
523    }
524  }
525
526  // Remove table from its RSGroup.
527  @Override
528  public void postDeleteTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
529                              TableName tableName) throws IOException {
530    try {
531      RSGroupInfo group = groupAdminServer.getRSGroupInfoOfTable(tableName);
532      if (group != null) {
533        LOG.debug(String.format("Removing deleted table '%s' from rsgroup '%s'", tableName,
534            group.getName()));
535        groupAdminServer.moveTables(Sets.newHashSet(tableName), null);
536      }
537    } catch (IOException ex) {
538      LOG.debug("Failed to perform RSGroup information cleanup for table: " + tableName, ex);
539    }
540  }
541
542  @Override
543  public void preCreateNamespace(ObserverContext<MasterCoprocessorEnvironment> ctx,
544                                 NamespaceDescriptor ns) throws IOException {
545    String group = ns.getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP);
546    if(group != null && groupAdminServer.getRSGroupInfo(group) == null) {
547      throw new ConstraintException("Region server group " + group + " does not exist.");
548    }
549  }
550
551  @Override
552  public void preModifyNamespace(ObserverContext<MasterCoprocessorEnvironment> ctx,
553      NamespaceDescriptor ns) throws IOException {
554    preCreateNamespace(ctx, ns);
555  }
556
557  @Override
558  public void preCloneSnapshot(ObserverContext<MasterCoprocessorEnvironment> ctx,
559      SnapshotDescription snapshot, TableDescriptor desc) throws IOException {
560    assignTableToGroup(desc);
561  }
562
563  @Override
564  public void postClearDeadServers(ObserverContext<MasterCoprocessorEnvironment> ctx,
565      List<ServerName> servers, List<ServerName> notClearedServers)
566      throws IOException {
567    Set<Address> clearedServer = servers.stream().
568        filter(server -> !notClearedServers.contains(server)).
569        map(ServerName::getAddress).
570        collect(Collectors.toSet());
571    if(!clearedServer.isEmpty()) {
572      groupAdminServer.removeServers(clearedServer);
573    }
574  }
575
576  public void checkPermission(String request) throws IOException {
577    accessChecker.requirePermission(getActiveUser(), request, null, Action.ADMIN);
578  }
579
580  /**
581   * Returns the active user to which authorization checks should be applied.
582   * If we are in the context of an RPC call, the remote user is used,
583   * otherwise the currently logged in user is used.
584   */
585  private User getActiveUser() throws IOException {
586    // for non-rpc handling, fallback to system user
587    Optional<User> optionalUser = RpcServer.getRequestUser();
588    if (optionalUser.isPresent()) {
589      return optionalUser.get();
590    }
591    return userProvider.getCurrent();
592  }
593}