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.Optional;
030import java.util.Set;
031import java.util.stream.Collectors;
032
033import org.apache.hadoop.hbase.CoprocessorEnvironment;
034import org.apache.hadoop.hbase.HBaseIOException;
035import org.apache.hadoop.hbase.HConstants;
036import org.apache.hadoop.hbase.MasterNotRunningException;
037import org.apache.hadoop.hbase.NamespaceDescriptor;
038import org.apache.hadoop.hbase.PleaseHoldException;
039import org.apache.hadoop.hbase.ServerName;
040import org.apache.hadoop.hbase.TableName;
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.TableProtos;
082import org.apache.hadoop.hbase.security.User;
083import org.apache.hadoop.hbase.security.UserProvider;
084import org.apache.hadoop.hbase.security.access.AccessChecker;
085import org.apache.hadoop.hbase.security.access.Permission.Action;
086import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
087import org.apache.yetus.audience.InterfaceAudience;
088import org.slf4j.Logger;
089import org.slf4j.LoggerFactory;
090import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
091
092// TODO: Encapsulate MasterObserver functions into separate subclass.
093@CoreCoprocessor
094@InterfaceAudience.Private
095public class RSGroupAdminEndpoint implements MasterCoprocessor, MasterObserver {
096  private static final Logger LOG = LoggerFactory.getLogger(RSGroupAdminEndpoint.class);
097
098  private MasterServices master = null;
099  // Only instance of RSGroupInfoManager. RSGroup aware load balancers ask for this instance on
100  // their setup.
101  private RSGroupInfoManager groupInfoManager;
102  private RSGroupAdminServer groupAdminServer;
103  private final RSGroupAdminService groupAdminService = new RSGroupAdminServiceImpl();
104  private AccessChecker accessChecker;
105
106  /** Provider for mapping principal names to Users */
107  private UserProvider userProvider;
108
109  @Override
110  public void start(CoprocessorEnvironment env) throws IOException {
111    if (!(env instanceof HasMasterServices)) {
112      throw new IOException("Does not implement HMasterServices");
113    }
114
115    master = ((HasMasterServices)env).getMasterServices();
116    groupInfoManager = RSGroupInfoManagerImpl.getInstance(master);
117    groupAdminServer = new RSGroupAdminServer(master, groupInfoManager);
118    Class<?> clazz =
119        master.getConfiguration().getClass(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, null);
120    if (!RSGroupableBalancer.class.isAssignableFrom(clazz)) {
121      throw new IOException("Configured balancer does not support RegionServer groups.");
122    }
123    ZKWatcher zk = ((HasMasterServices)env).getMasterServices().getZooKeeper();
124    accessChecker = new AccessChecker(env.getConfiguration(), zk);
125
126    // set the user-provider.
127    this.userProvider = UserProvider.instantiate(env.getConfiguration());
128  }
129
130  @Override
131  public void stop(CoprocessorEnvironment env) {
132    accessChecker.stop();
133  }
134
135  @Override
136  public Iterable<Service> getServices() {
137    return Collections.singleton(groupAdminService);
138  }
139
140  @Override
141  public Optional<MasterObserver> getMasterObserver() {
142    return Optional.of(this);
143  }
144
145  RSGroupInfoManager getGroupInfoManager() {
146    return groupInfoManager;
147  }
148
149  /**
150   * Implementation of RSGroupAdminService defined in RSGroupAdmin.proto.
151   * This class calls {@link RSGroupAdminServer} for actual work, converts result to protocol
152   * buffer response, handles exceptions if any occurred and then calls the {@code RpcCallback} with
153   * the response.
154   */
155  private class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
156    @Override
157    public void getRSGroupInfo(RpcController controller,
158        GetRSGroupInfoRequest request, RpcCallback<GetRSGroupInfoResponse> done) {
159      GetRSGroupInfoResponse.Builder builder = GetRSGroupInfoResponse.newBuilder();
160      String groupName = request.getRSGroupName();
161      LOG.info(master.getClientIdAuditPrefix() + " initiates rsgroup info retrieval, group="
162              + groupName);
163      try {
164        checkPermission("getRSGroupInfo");
165        RSGroupInfo rsGroupInfo = groupAdminServer.getRSGroupInfo(groupName);
166        if (rsGroupInfo != null) {
167          builder.setRSGroupInfo(RSGroupProtobufUtil.toProtoGroupInfo(rsGroupInfo));
168        }
169      } catch (IOException e) {
170        CoprocessorRpcUtils.setControllerException(controller, e);
171      }
172      done.run(builder.build());
173    }
174
175    @Override
176    public void getRSGroupInfoOfTable(RpcController controller,
177        GetRSGroupInfoOfTableRequest request, RpcCallback<GetRSGroupInfoOfTableResponse> done) {
178      GetRSGroupInfoOfTableResponse.Builder builder = GetRSGroupInfoOfTableResponse.newBuilder();
179      TableName tableName = ProtobufUtil.toTableName(request.getTableName());
180      LOG.info(master.getClientIdAuditPrefix() + " initiates rsgroup info retrieval, table="
181          + tableName);
182      try {
183        checkPermission("getRSGroupInfoOfTable");
184        RSGroupInfo RSGroupInfo = groupAdminServer.getRSGroupInfoOfTable(tableName);
185        if (RSGroupInfo != null) {
186          builder.setRSGroupInfo(RSGroupProtobufUtil.toProtoGroupInfo(RSGroupInfo));
187        }
188      } catch (IOException e) {
189        CoprocessorRpcUtils.setControllerException(controller, e);
190      }
191      done.run(builder.build());
192    }
193
194    @Override
195    public void moveServers(RpcController controller, MoveServersRequest request,
196        RpcCallback<MoveServersResponse> done) {
197      MoveServersResponse.Builder builder = MoveServersResponse.newBuilder();
198      Set<Address> hostPorts = Sets.newHashSet();
199      for (HBaseProtos.ServerName el : request.getServersList()) {
200        hostPorts.add(Address.fromParts(el.getHostName(), el.getPort()));
201      }
202      LOG.info(master.getClientIdAuditPrefix() + " move servers " + hostPorts +" to rsgroup "
203          + request.getTargetGroup());
204      try {
205        if (master.getMasterCoprocessorHost() != null) {
206          master.getMasterCoprocessorHost().preMoveServers(hostPorts, request.getTargetGroup());
207        }
208        checkPermission("moveServers");
209        groupAdminServer.moveServers(hostPorts, request.getTargetGroup());
210        if (master.getMasterCoprocessorHost() != null) {
211          master.getMasterCoprocessorHost().postMoveServers(hostPorts, request.getTargetGroup());
212        }
213      } catch (IOException e) {
214        CoprocessorRpcUtils.setControllerException(controller, e);
215      }
216      done.run(builder.build());
217    }
218
219    @Override
220    public void moveTables(RpcController controller, MoveTablesRequest request,
221        RpcCallback<MoveTablesResponse> done) {
222      MoveTablesResponse.Builder builder = MoveTablesResponse.newBuilder();
223      Set<TableName> tables = new HashSet<>(request.getTableNameList().size());
224      for (TableProtos.TableName tableName : request.getTableNameList()) {
225        tables.add(ProtobufUtil.toTableName(tableName));
226      }
227      LOG.info(master.getClientIdAuditPrefix() + " move tables " + tables +" to rsgroup "
228          + request.getTargetGroup());
229      try {
230        if (master.getMasterCoprocessorHost() != null) {
231          master.getMasterCoprocessorHost().preMoveTables(tables, request.getTargetGroup());
232        }
233        checkPermission("moveTables");
234        groupAdminServer.moveTables(tables, request.getTargetGroup());
235        if (master.getMasterCoprocessorHost() != null) {
236          master.getMasterCoprocessorHost().postMoveTables(tables, request.getTargetGroup());
237        }
238      } catch (IOException e) {
239        CoprocessorRpcUtils.setControllerException(controller, e);
240      }
241      done.run(builder.build());
242    }
243
244    @Override
245    public void addRSGroup(RpcController controller, AddRSGroupRequest request,
246        RpcCallback<AddRSGroupResponse> done) {
247      AddRSGroupResponse.Builder builder = AddRSGroupResponse.newBuilder();
248      LOG.info(master.getClientIdAuditPrefix() + " add rsgroup " + request.getRSGroupName());
249      try {
250        if (master.getMasterCoprocessorHost() != null) {
251          master.getMasterCoprocessorHost().preAddRSGroup(request.getRSGroupName());
252        }
253        checkPermission("addRSGroup");
254        groupAdminServer.addRSGroup(request.getRSGroupName());
255        if (master.getMasterCoprocessorHost() != null) {
256          master.getMasterCoprocessorHost().postAddRSGroup(request.getRSGroupName());
257        }
258      } catch (IOException e) {
259        CoprocessorRpcUtils.setControllerException(controller, e);
260      }
261      done.run(builder.build());
262    }
263
264    @Override
265    public void removeRSGroup(RpcController controller,
266        RemoveRSGroupRequest request, RpcCallback<RemoveRSGroupResponse> done) {
267      RemoveRSGroupResponse.Builder builder =
268          RemoveRSGroupResponse.newBuilder();
269      LOG.info(master.getClientIdAuditPrefix() + " remove rsgroup " + request.getRSGroupName());
270      try {
271        if (master.getMasterCoprocessorHost() != null) {
272          master.getMasterCoprocessorHost().preRemoveRSGroup(request.getRSGroupName());
273        }
274        checkPermission("removeRSGroup");
275        groupAdminServer.removeRSGroup(request.getRSGroupName());
276        if (master.getMasterCoprocessorHost() != null) {
277          master.getMasterCoprocessorHost().postRemoveRSGroup(request.getRSGroupName());
278        }
279      } catch (IOException e) {
280        CoprocessorRpcUtils.setControllerException(controller, e);
281      }
282      done.run(builder.build());
283    }
284
285    @Override
286    public void balanceRSGroup(RpcController controller,
287        BalanceRSGroupRequest request, RpcCallback<BalanceRSGroupResponse> done) {
288      BalanceRSGroupResponse.Builder builder = BalanceRSGroupResponse.newBuilder();
289      LOG.info(master.getClientIdAuditPrefix() + " balance rsgroup, group="
290          + request.getRSGroupName());
291      try {
292        if (master.getMasterCoprocessorHost() != null) {
293          master.getMasterCoprocessorHost().preBalanceRSGroup(request.getRSGroupName());
294        }
295        checkPermission("balanceRSGroup");
296        boolean balancerRan = groupAdminServer.balanceRSGroup(request.getRSGroupName());
297        builder.setBalanceRan(balancerRan);
298        if (master.getMasterCoprocessorHost() != null) {
299          master.getMasterCoprocessorHost().postBalanceRSGroup(request.getRSGroupName(),
300              balancerRan);
301        }
302      } catch (IOException e) {
303        CoprocessorRpcUtils.setControllerException(controller, e);
304        builder.setBalanceRan(false);
305      }
306      done.run(builder.build());
307    }
308
309    @Override
310    public void listRSGroupInfos(RpcController controller,
311        ListRSGroupInfosRequest request, RpcCallback<ListRSGroupInfosResponse> done) {
312      ListRSGroupInfosResponse.Builder builder = ListRSGroupInfosResponse.newBuilder();
313      LOG.info(master.getClientIdAuditPrefix() + " list rsgroup");
314      try {
315        checkPermission("listRSGroup");
316        for (RSGroupInfo RSGroupInfo : groupAdminServer.listRSGroups()) {
317          builder.addRSGroupInfo(RSGroupProtobufUtil.toProtoGroupInfo(RSGroupInfo));
318        }
319      } catch (IOException e) {
320        CoprocessorRpcUtils.setControllerException(controller, e);
321      }
322      done.run(builder.build());
323    }
324
325    @Override
326    public void getRSGroupInfoOfServer(RpcController controller,
327        GetRSGroupInfoOfServerRequest request, RpcCallback<GetRSGroupInfoOfServerResponse> done) {
328      GetRSGroupInfoOfServerResponse.Builder builder = GetRSGroupInfoOfServerResponse.newBuilder();
329      Address hp = Address.fromParts(request.getServer().getHostName(),
330          request.getServer().getPort());
331      LOG.info(master.getClientIdAuditPrefix() + " initiates rsgroup info retrieval, server="
332          + hp);
333      try {
334        checkPermission("getRSGroupInfoOfServer");
335        RSGroupInfo info = groupAdminServer.getRSGroupOfServer(hp);
336        if (info != null) {
337          builder.setRSGroupInfo(RSGroupProtobufUtil.toProtoGroupInfo(info));
338        }
339      } catch (IOException e) {
340        CoprocessorRpcUtils.setControllerException(controller, e);
341      }
342      done.run(builder.build());
343    }
344
345    @Override
346    public void moveServersAndTables(RpcController controller,
347        MoveServersAndTablesRequest request, RpcCallback<MoveServersAndTablesResponse> done) {
348      MoveServersAndTablesResponse.Builder builder = MoveServersAndTablesResponse.newBuilder();
349      Set<Address> hostPorts = Sets.newHashSet();
350      for (HBaseProtos.ServerName el : request.getServersList()) {
351        hostPorts.add(Address.fromParts(el.getHostName(), el.getPort()));
352      }
353      Set<TableName> tables = new HashSet<>(request.getTableNameList().size());
354      for (TableProtos.TableName tableName : request.getTableNameList()) {
355        tables.add(ProtobufUtil.toTableName(tableName));
356      }
357      LOG.info(master.getClientIdAuditPrefix() + " move servers " + hostPorts
358          + " and tables " + tables + " to rsgroup" + request.getTargetGroup());
359      try {
360        if (master.getMasterCoprocessorHost() != null) {
361          master.getMasterCoprocessorHost().preMoveServersAndTables(hostPorts, tables,
362              request.getTargetGroup());
363        }
364        checkPermission("moveServersAndTables");
365        groupAdminServer.moveServersAndTables(hostPorts, tables, request.getTargetGroup());
366        if (master.getMasterCoprocessorHost() != null) {
367          master.getMasterCoprocessorHost().postMoveServersAndTables(hostPorts, tables,
368              request.getTargetGroup());
369        }
370      } catch (IOException e) {
371        CoprocessorRpcUtils.setControllerException(controller, e);
372      }
373      done.run(builder.build());
374    }
375
376    @Override
377    public void removeServers(RpcController controller,
378        RemoveServersRequest request,
379        RpcCallback<RemoveServersResponse> done) {
380      RemoveServersResponse.Builder builder =
381          RemoveServersResponse.newBuilder();
382      Set<Address> servers = Sets.newHashSet();
383      for (HBaseProtos.ServerName el : request.getServersList()) {
384        servers.add(Address.fromParts(el.getHostName(), el.getPort()));
385      }
386      LOG.info(master.getClientIdAuditPrefix()
387          + " remove decommissioned servers from rsgroup: " + servers);
388      try {
389        if (master.getMasterCoprocessorHost() != null) {
390          master.getMasterCoprocessorHost().preRemoveServers(servers);
391        }
392        checkPermission("removeServers");
393        groupAdminServer.removeServers(servers);
394        if (master.getMasterCoprocessorHost() != null) {
395          master.getMasterCoprocessorHost().postRemoveServers(servers);
396        }
397      } catch (IOException e) {
398        CoprocessorRpcUtils.setControllerException(controller, e);
399      }
400      done.run(builder.build());
401    }
402  }
403
404  boolean rsgroupHasServersOnline(TableDescriptor desc) throws IOException {
405    String groupName;
406    try {
407      groupName =
408        master.getClusterSchema().getNamespace(desc.getTableName().getNamespaceAsString())
409        .getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP);
410      if (groupName == null) {
411        groupName = RSGroupInfo.DEFAULT_GROUP;
412      }
413    } catch (MasterNotRunningException | PleaseHoldException e) {
414      LOG.info("Master has not initialized yet; temporarily using default RSGroup '" +
415          RSGroupInfo.DEFAULT_GROUP + "' for deploy of system table");
416      groupName = RSGroupInfo.DEFAULT_GROUP;
417    }
418
419    RSGroupInfo rsGroupInfo = groupAdminServer.getRSGroupInfo(groupName);
420    if (rsGroupInfo == null) {
421      throw new ConstraintException(
422          "Default RSGroup (" + groupName + ") for this table's " + "namespace does not exist.");
423    }
424
425    for (ServerName onlineServer : master.getServerManager().createDestinationServersList()) {
426      if (rsGroupInfo.getServers().contains(onlineServer.getAddress())) {
427        return true;
428      }
429    }
430    return false;
431  }
432
433  void assignTableToGroup(TableDescriptor desc) throws IOException {
434    String groupName =
435        master.getClusterSchema().getNamespace(desc.getTableName().getNamespaceAsString())
436                .getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP);
437    if (groupName == null) {
438      groupName = RSGroupInfo.DEFAULT_GROUP;
439    }
440    RSGroupInfo rsGroupInfo = groupAdminServer.getRSGroupInfo(groupName);
441    if (rsGroupInfo == null) {
442      throw new ConstraintException("Default RSGroup (" + groupName + ") for this table's "
443          + "namespace does not exist.");
444    }
445    if (!rsGroupInfo.containsTable(desc.getTableName())) {
446      LOG.debug("Pre-moving table " + desc.getTableName() + " to RSGroup " + groupName);
447      groupAdminServer.moveTables(Sets.newHashSet(desc.getTableName()), groupName);
448    }
449  }
450
451  /////////////////////////////////////////////////////////////////////////////
452  // MasterObserver overrides
453  /////////////////////////////////////////////////////////////////////////////
454
455  @Override
456  public void preCreateTableAction(
457      final ObserverContext<MasterCoprocessorEnvironment> ctx,
458      final TableDescriptor desc,
459      final RegionInfo[] regions) throws IOException {
460    if (!desc.getTableName().isSystemTable() && !rsgroupHasServersOnline(desc)) {
461      throw new HBaseIOException("No online servers in the rsgroup, which table " +
462          desc.getTableName().getNameAsString() + " belongs to");
463    }
464  }
465
466  // Assign table to default RSGroup.
467  @Override
468  public void postCreateTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
469      TableDescriptor desc, RegionInfo[] regions) throws IOException {
470    assignTableToGroup(desc);
471  }
472
473  // Remove table from its RSGroup.
474  @Override
475  public void postDeleteTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
476                              TableName tableName) throws IOException {
477    try {
478      RSGroupInfo group = groupAdminServer.getRSGroupInfoOfTable(tableName);
479      if (group != null) {
480        LOG.debug(String.format("Removing deleted table '%s' from rsgroup '%s'", tableName,
481            group.getName()));
482        groupAdminServer.moveTables(Sets.newHashSet(tableName), null);
483      }
484    } catch (IOException ex) {
485      LOG.debug("Failed to perform RSGroup information cleanup for table: " + tableName, ex);
486    }
487  }
488
489  @Override
490  public void preCreateNamespace(ObserverContext<MasterCoprocessorEnvironment> ctx,
491                                 NamespaceDescriptor ns) throws IOException {
492    String group = ns.getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP);
493    if(group != null && groupAdminServer.getRSGroupInfo(group) == null) {
494      throw new ConstraintException("Region server group "+group+" does not exit");
495    }
496  }
497
498  @Override
499  public void preModifyNamespace(ObserverContext<MasterCoprocessorEnvironment> ctx,
500      NamespaceDescriptor ns) throws IOException {
501    preCreateNamespace(ctx, ns);
502  }
503
504  @Override
505  public void preCloneSnapshot(ObserverContext<MasterCoprocessorEnvironment> ctx,
506      SnapshotDescription snapshot, TableDescriptor desc) throws IOException {
507    assignTableToGroup(desc);
508  }
509
510  @Override
511  public void postClearDeadServers(ObserverContext<MasterCoprocessorEnvironment> ctx,
512      List<ServerName> servers, List<ServerName> notClearedServers)
513      throws IOException {
514    Set<Address> clearedServer = servers.stream().
515        filter(server -> !notClearedServers.contains(server)).
516        map(ServerName::getAddress).
517        collect(Collectors.toSet());
518    groupAdminServer.removeServers(clearedServer);
519  }
520
521  public void checkPermission(String request) throws IOException {
522    accessChecker.requirePermission(getActiveUser(), request, Action.ADMIN);
523  }
524
525  /**
526   * Returns the active user to which authorization checks should be applied.
527   * If we are in the context of an RPC call, the remote user is used,
528   * otherwise the currently logged in user is used.
529   */
530  private User getActiveUser() throws IOException {
531    // for non-rpc handling, fallback to system user
532    Optional<User> optionalUser = RpcServer.getRequestUser();
533    if (optionalUser.isPresent()) {
534      return optionalUser.get();
535    }
536    return userProvider.getCurrent();
537  }
538}