@Override
  protected Pair<Integer, String> exec(String hostname, ServiceType service, String... cmd)
    throws IOException {
    if (!supportedServices.contains(service)) {
      throw unsupportedServiceType(service);
    }

    // We only support actions vs. Master or Region Server processes. We're issuing those actions
    // via the coprocessor that's running within those processes. Thus, there's no support for
    // honoring the configured service user.
    final String command = StringUtils.join(cmd, " ");
    LOG.info("Executing remote command: {}, hostname:{}", command, hostname);

    try (final AsyncConnection conn = ConnectionFactory.createAsyncConnection(getConf()).join()) {
      final AsyncAdmin admin = conn.getAdmin();
      final ShellExecRequest req =
        ShellExecRequest.newBuilder().setCommand(command).setAwaitResponse(false).build();

      final ShellExecResponse resp;
      switch (service) {
        case HBASE_MASTER:
          // What happens if the intended action was killing a backup master? Right now we have
          // no `RestartBackupMasterAction` so it's probably fine.
          resp = masterExec(admin, req);
          break;
        case HBASE_REGIONSERVER:
          final ServerName targetHost = resolveRegionServerName(admin, hostname);
          resp = regionServerExec(admin, req, targetHost);
          break;
        default:
          throw new RuntimeException("should not happen");
      }

      if (LOG.isDebugEnabled()) {
        LOG.debug("Executed remote command: {}, exit code:{} , output:{}", command,
          resp.getExitCode(), resp.getStdout());
      } else {
        LOG.info("Executed remote command: {}, exit code:{}", command, resp.getExitCode());
      }
      return new Pair<>(resp.getExitCode(), resp.getStdout());
    }
  }
Overrides commands to make use of coprocessor where possible. Only supports actions taken against
Master and Region Server hosts.
hbase-it/src/test/java/org/apache/hadoop/hbase/CoprocClusterManager.java