<commit_before>/*
 * 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.accumulo.cluster.standalone;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;

import org.apache.accumulo.cluster.ClusterControl;
import org.apache.accumulo.cluster.RemoteShell;
import org.apache.accumulo.cluster.RemoteShellOptions;
import org.apache.accumulo.minicluster.ServerType;
import org.apache.accumulo.server.util.Admin;
import org.apache.hadoop.util.Shell.ExitCodeException;

import com.google.common.collect.Maps;

/**
 * Use the {@link RemoteShell} to control a standalone (possibly distibuted) Accumulo instance
 */
public class StandaloneClusterControl implements ClusterControl {

  protected String accumuloHome, accumuloConfDir;
  protected RemoteShellOptions options;

  protected String startServerPath, accumuloPath;

  public StandaloneClusterControl() {
    this(System.getenv("ACCUMULO_HOME"), System.getenv("ACCUMULO_CONF_DIR"));
  }

  public StandaloneClusterControl(String accumuloHome, String accumuloConfDir) {
    this.options = new RemoteShellOptions();
    this.accumuloHome = accumuloHome;
    this.accumuloConfDir = accumuloConfDir;

    File bin = new File(accumuloHome, "bin");
    File startServer = new File(bin, "start-server.sh");
    this.startServerPath = startServer.getAbsolutePath();
    File accumulo = new File(bin, "accumulo");
    this.accumuloPath = accumulo.getAbsolutePath();
  }

  protected Entry<Integer,String> exec(String hostname, String[] command) throws IOException {
    RemoteShell shell = new RemoteShell(hostname, command, options);
    try {
      shell.execute();
    } catch (ExitCodeException e) {
      // capture the stdout of the process as well.
      String output = shell.getOutput();
      // add output for the ExitCodeException.
      throw new ExitCodeException(e.getExitCode(), "stderr: " + e.getMessage() + ", stdout: " + output);
    }

    return Maps.immutableEntry(shell.getExitCode(), shell.getOutput());
  }

  @Override
  public int exec(Class<?> clz, String[] args) throws IOException {
    File confDir = getConfDir();
    String master = getHosts(new File(confDir, "masters")).get(0);
    String[] cmd = new String[2 + args.length];
    cmd[0] = accumuloPath;
    cmd[1] = clz.getName();
    System.arraycopy(args, 0, cmd, 2, args.length);
    return exec(master, cmd).getKey();
  }

  @Override
  public void adminStopAll() throws IOException {
    File confDir = getConfDir();
    String master = getHosts(new File(confDir, "masters")).get(0);
    String[] cmd = new String[] { accumuloPath, Admin.class.getName(), "stopAll" };
    exec(master, cmd);
  }

  @Override
  public void startAllServers(ServerType server) throws IOException {
    File confDir = getConfDir();

    switch (server) {
      case TABLET_SERVER:
        for (String tserver : getHosts(new File(confDir, "slaves"))) {
          start(server, tserver);
        }
        break;<commit_msg>ACCUMULO-3167 Include a nice log.info message for the command being exec'ed.<commit_after>/*
 * 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.accumulo.cluster.standalone;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;

import org.apache.accumulo.cluster.ClusterControl;
import org.apache.accumulo.cluster.RemoteShell;
import org.apache.accumulo.cluster.RemoteShellOptions;
import org.apache.accumulo.minicluster.ServerType;
import org.apache.accumulo.server.util.Admin;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.util.Shell.ExitCodeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Maps;

/**
 * Use the {@link RemoteShell} to control a standalone (possibly distibuted) Accumulo instance
 */
public class StandaloneClusterControl implements ClusterControl {
  private static final Logger log = LoggerFactory.getLogger(StandaloneClusterControl.class);

  protected String accumuloHome, accumuloConfDir;
  protected RemoteShellOptions options;

  protected String startServerPath, accumuloPath;

  public StandaloneClusterControl() {
    this(System.getenv("ACCUMULO_HOME"), System.getenv("ACCUMULO_CONF_DIR"));
  }

  public StandaloneClusterControl(String accumuloHome, String accumuloConfDir) {
    this.options = new RemoteShellOptions();
    this.accumuloHome = accumuloHome;
    this.accumuloConfDir = accumuloConfDir;

    File bin = new File(accumuloHome, "bin");
    File startServer = new File(bin, "start-server.sh");
    this.startServerPath = startServer.getAbsolutePath();
    File accumulo = new File(bin, "accumulo");
    this.accumuloPath = accumulo.getAbsolutePath();
  }

  protected Entry<Integer,String> exec(String hostname, String[] command) throws IOException {
    RemoteShell shell = new RemoteShell(hostname, command, options);
    try {
      shell.execute();
    } catch (ExitCodeException e) {
      // capture the stdout of the process as well.
      String output = shell.getOutput();
      // add output for the ExitCodeException.
      throw new ExitCodeException(e.getExitCode(), "stderr: " + e.getMessage() + ", stdout: " + output);
    }

    return Maps.immutableEntry(shell.getExitCode(), shell.getOutput());
  }

  @Override
  public int exec(Class<?> clz, String[] args) throws IOException {
    File confDir = getConfDir();
    String master = getHosts(new File(confDir, "masters")).get(0);
    String[] cmd = new String[2 + args.length];
    cmd[0] = accumuloPath;
    cmd[1] = clz.getName();
    System.arraycopy(args, 0, cmd, 2, args.length);
    log.info("Running: '{}' on {}", StringUtils.join(cmd, " "), master);
    return exec(master, cmd).getKey();
  }

  @Override
  public void adminStopAll() throws IOException {
    File confDir = getConfDir();
    String master = getHosts(new File(confDir, "masters")).get(0);
    String[] cmd = new String[] { accumuloPath, Admin.class.getName(), "stopAll" };
    exec(master, cmd);
  }

  @Override
  public void startAllServers(ServerType server) throws IOException {
    File confDir = getConfDir();

    switch (server) {
      case TABLET_SERVER:
        for (String tserver : getHosts(new File(confDir, "slaves"))) {
          start(server, tserver);
        }
        break;
{'fraction_non_alphanumeric': 0.10521042084168336, 'fraction_numerical': 0.0035070140280561123, 'mean_word_length': 4.154938670109749, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5715658', 'n_tokens_mistral': 2308, 'n_tokens_neox': 2253, 'n_words': 687}