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.zookeeper;
019
020import java.io.File;
021import java.io.IOException;
022import java.io.PrintWriter;
023import java.net.InetAddress;
024import java.net.NetworkInterface;
025import java.nio.charset.StandardCharsets;
026import java.util.ArrayList;
027import java.util.Enumeration;
028import java.util.List;
029import java.util.Map.Entry;
030import java.util.Properties;
031import org.apache.hadoop.conf.Configuration;
032import org.apache.hadoop.hbase.HBaseConfiguration;
033import org.apache.hadoop.hbase.HBaseInterfaceAudience;
034import org.apache.hadoop.hbase.HConstants;
035import org.apache.hadoop.hbase.util.DNS;
036import org.apache.hadoop.hbase.util.Strings;
037import org.apache.hadoop.util.StringUtils;
038import org.apache.yetus.audience.InterfaceAudience;
039import org.apache.yetus.audience.InterfaceStability;
040import org.apache.zookeeper.server.DatadirCleanupManager;
041import org.apache.zookeeper.server.ServerConfig;
042import org.apache.zookeeper.server.ZooKeeperServerMain;
043import org.apache.zookeeper.server.admin.AdminServer;
044import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
045import org.apache.zookeeper.server.quorum.QuorumPeerMain;
046
047/**
048 * HBase's version of ZooKeeper's QuorumPeer. When HBase is set to manage ZooKeeper, this class is
049 * used to start up QuorumPeer instances. By doing things in here rather than directly calling to
050 * ZooKeeper, we have more control over the process. This class uses {@link ZKConfig} to get
051 * settings from the hbase-site.xml file.
052 */
053@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS)
054@InterfaceStability.Evolving
055public final class HQuorumPeer {
056  private HQuorumPeer() {
057  }
058
059  /**
060   * Parse ZooKeeper configuration from HBase XML config and run a QuorumPeer.
061   * @param args String[] of command line arguments. Not used.
062   */
063  public static void main(String[] args) {
064    Configuration conf = HBaseConfiguration.create();
065    try {
066      Properties zkProperties = ZKConfig.makeZKProps(conf);
067      writeMyID(zkProperties);
068      QuorumPeerConfig zkConfig = new QuorumPeerConfig();
069      zkConfig.parseProperties(zkProperties);
070
071      // login the zookeeper server principal (if using security)
072      ZKAuthentication.loginServer(conf, HConstants.ZK_SERVER_KEYTAB_FILE,
073        HConstants.ZK_SERVER_KERBEROS_PRINCIPAL, zkConfig.getClientPortAddress().getHostName());
074
075      runZKServer(zkConfig);
076    } catch (Exception e) {
077      e.printStackTrace();
078      System.exit(-1);
079    }
080  }
081
082  private static void runZKServer(QuorumPeerConfig zkConfig)
083    throws IOException, AdminServer.AdminServerException {
084
085    /**
086     * Start and schedule the purge task autopurge.purgeInterval is 0 by default,so in fact the
087     * DatadirCleanupManager task will not be started to clean the logs by default. Config is
088     * recommended only for standalone server.
089     */
090
091    DatadirCleanupManager purgeMgr = new DatadirCleanupManager(zkConfig.getDataDir(),
092      zkConfig.getDataLogDir(), zkConfig.getSnapRetainCount(), zkConfig.getPurgeInterval());
093    purgeMgr.start();
094
095    if (zkConfig.isDistributed()) {
096      QuorumPeerMain qp = new QuorumPeerMain();
097      qp.runFromConfig(zkConfig);
098    } else {
099      ZooKeeperServerMain zk = new ZooKeeperServerMain();
100      ServerConfig serverConfig = new ServerConfig();
101      serverConfig.readFrom(zkConfig);
102      zk.runFromConfig(serverConfig);
103    }
104  }
105
106  private static boolean addressIsLocalHost(String address) {
107    return address.equals("localhost") || address.equals("127.0.0.1");
108  }
109
110  static void writeMyID(Properties properties) throws IOException {
111    long myId = -1;
112
113    Configuration conf = HBaseConfiguration.create();
114    String myAddress = Strings.domainNamePointerToHostName(
115      DNS.getDefaultHost(conf.get("hbase.zookeeper.dns.interface", "default"),
116        conf.get("hbase.zookeeper.dns.nameserver", "default")));
117
118    List<String> ips = new ArrayList<>();
119
120    // Add what could be the best (configured) match
121    ips.add(myAddress.contains(".") ? myAddress : StringUtils.simpleHostname(myAddress));
122
123    // For all nics get all hostnames and IPs
124    Enumeration<?> nics = NetworkInterface.getNetworkInterfaces();
125    while (nics.hasMoreElements()) {
126      Enumeration<?> rawAdrs = ((NetworkInterface) nics.nextElement()).getInetAddresses();
127      while (rawAdrs.hasMoreElements()) {
128        InetAddress inet = (InetAddress) rawAdrs.nextElement();
129        ips.add(StringUtils.simpleHostname(inet.getHostName()));
130        ips.add(inet.getHostAddress());
131      }
132    }
133
134    for (Entry<Object, Object> entry : properties.entrySet()) {
135      String key = entry.getKey().toString().trim();
136      String value = entry.getValue().toString().trim();
137      if (key.startsWith("server.")) {
138        int dot = key.indexOf('.');
139        long id = Long.parseLong(key.substring(dot + 1));
140        String[] parts = value.split(":");
141        String address = parts[0];
142        if (addressIsLocalHost(address) || ips.contains(address)) {
143          myId = id;
144          break;
145        }
146      }
147    }
148
149    // Set the max session timeout from the provided client-side timeout
150    properties.setProperty("maxSessionTimeout", conf.get(HConstants.ZK_SESSION_TIMEOUT,
151      Integer.toString(HConstants.DEFAULT_ZK_SESSION_TIMEOUT)));
152
153    if (myId == -1) {
154      throw new IOException(
155        "Could not find my address: " + myAddress + " in list of ZooKeeper quorum servers");
156    }
157
158    String dataDirStr = properties.get("dataDir").toString().trim();
159    File dataDir = new File(dataDirStr);
160    if (!dataDir.isDirectory()) {
161      if (!dataDir.mkdirs()) {
162        throw new IOException("Unable to create data dir " + dataDir);
163      }
164    }
165
166    File myIdFile = new File(dataDir, "myid");
167    PrintWriter w = new PrintWriter(myIdFile, StandardCharsets.UTF_8.name());
168    w.println(myId);
169    w.close();
170  }
171}