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.util;
019
020import static org.apache.hadoop.hbase.util.Threads.isNonDaemonThreadRunning;
021
022import java.lang.management.ManagementFactory;
023import java.lang.management.RuntimeMXBean;
024import java.util.Arrays;
025import java.util.HashSet;
026import java.util.Locale;
027import java.util.Map.Entry;
028import java.util.Set;
029import org.apache.hadoop.conf.Configuration;
030import org.apache.hadoop.conf.Configured;
031import org.apache.hadoop.hbase.HBaseConfiguration;
032import org.apache.hadoop.hbase.HConstants;
033import org.apache.hadoop.util.Tool;
034import org.apache.hadoop.util.ToolRunner;
035import org.apache.yetus.audience.InterfaceAudience;
036import org.slf4j.Logger;
037import org.slf4j.LoggerFactory;
038
039/**
040 * Base class for command lines that start up various HBase daemons.
041 */
042@InterfaceAudience.Private
043public abstract class ServerCommandLine extends Configured implements Tool {
044  private static final Logger LOG = LoggerFactory.getLogger(ServerCommandLine.class);
045  @SuppressWarnings("serial")
046  private static final Set<String> DEFAULT_SKIP_WORDS = new HashSet<String>() {
047    {
048      add("secret");
049      add("passwd");
050      add("password");
051      add("credential");
052    }
053  };
054
055  /**
056   * Implementing subclasses should return a usage string to print out.
057   */
058  protected abstract String getUsage();
059
060  /**
061   * Print usage information for this command line.
062   * @param message if not null, print this message before the usage info.
063   */
064  protected void usage(String message) {
065    if (message != null) {
066      System.err.println(message);
067      System.err.println("");
068    }
069
070    System.err.println(getUsage());
071  }
072
073  /**
074   * Log information about the currently running JVM.
075   */
076  public static void logJVMInfo() {
077    // Print out vm stats before starting up.
078    RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
079    if (runtime != null) {
080      LOG.info("vmName=" + runtime.getVmName() + ", vmVendor=" + runtime.getVmVendor()
081        + ", vmVersion=" + runtime.getVmVersion());
082      LOG.info("vmInputArguments=" + runtime.getInputArguments());
083    }
084  }
085
086  /**
087   * Print into log some of the important hbase attributes.
088   */
089  private static void logHBaseConfigs(Configuration conf) {
090    final String[] keys = new String[] {
091      // Expand this list as you see fit.
092      "hbase.tmp.dir", HConstants.HBASE_DIR, HConstants.CLUSTER_DISTRIBUTED,
093      HConstants.ZOOKEEPER_QUORUM,
094
095    };
096    for (String key : keys) {
097      LOG.info(key + ": " + conf.get(key));
098    }
099  }
100
101  /**
102   * Logs information about the currently running JVM process including the environment variables.
103   * Logging of env vars can be disabled by setting {@code "hbase.envvars.logging.disabled"} to
104   * {@code "true"}.
105   * <p>
106   * If enabled, you can also exclude environment variables containing certain substrings by setting
107   * {@code "hbase.envvars.logging.skipwords"} to comma separated list of such substrings.
108   */
109  public static void logProcessInfo(Configuration conf) {
110    logHBaseConfigs(conf);
111
112    // log environment variables unless asked not to
113    if (conf == null || !conf.getBoolean("hbase.envvars.logging.disabled", false)) {
114      Set<String> skipWords = new HashSet<>(DEFAULT_SKIP_WORDS);
115      if (conf != null) {
116        String[] confSkipWords = conf.getStrings("hbase.envvars.logging.skipwords");
117        if (confSkipWords != null) {
118          skipWords.addAll(Arrays.asList(confSkipWords));
119        }
120      }
121
122      nextEnv: for (Entry<String, String> entry : System.getenv().entrySet()) {
123        String key = entry.getKey().toLowerCase(Locale.ROOT);
124        String value = entry.getValue().toLowerCase(Locale.ROOT);
125        // exclude variables which may contain skip words
126        for (String skipWord : skipWords) {
127          if (key.contains(skipWord) || value.contains(skipWord)) continue nextEnv;
128        }
129        LOG.info("env:" + entry);
130      }
131    }
132
133    // and JVM info
134    logJVMInfo();
135  }
136
137  /**
138   * Parse and run the given command line. This will exit the JVM with the exit code returned from
139   * <code>run()</code>. If return code is 0, wait for atmost 30 seconds for all non-daemon threads
140   * to quit, otherwise exit the jvm
141   */
142  public void doMain(String args[]) {
143    try {
144      int ret = ToolRunner.run(HBaseConfiguration.create(), this, args);
145      if (ret != 0) {
146        System.exit(ret);
147      }
148      // Return code is 0 here.
149      boolean forceStop = false;
150      long startTime = EnvironmentEdgeManager.currentTime();
151      while (isNonDaemonThreadRunning()) {
152        if (EnvironmentEdgeManager.currentTime() - startTime > 30 * 1000) {
153          forceStop = true;
154          break;
155        }
156        Thread.sleep(1000);
157      }
158      if (forceStop) {
159        LOG.error("Failed to stop all non-daemon threads, so terminating JVM");
160        System.exit(-1);
161      }
162    } catch (Exception e) {
163      LOG.error("Failed to run", e);
164      System.exit(-1);
165    }
166  }
167}