View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.master;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.util.List;
24  
25  import org.apache.commons.cli.CommandLine;
26  import org.apache.commons.cli.GnuParser;
27  import org.apache.commons.cli.Options;
28  import org.apache.commons.cli.ParseException;
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.classification.InterfaceAudience;
32  import org.apache.hadoop.conf.Configuration;
33  import org.apache.hadoop.hbase.ZNodeClearer;
34  import org.apache.hadoop.hbase.HConstants;
35  import org.apache.hadoop.hbase.LocalHBaseCluster;
36  import org.apache.hadoop.hbase.exceptions.MasterNotRunningException;
37  import org.apache.hadoop.hbase.exceptions.ZooKeeperConnectionException;
38  import org.apache.hadoop.hbase.client.HBaseAdmin;
39  import org.apache.hadoop.hbase.regionserver.HRegionServer;
40  import org.apache.hadoop.hbase.util.JVMClusterUtil;
41  import org.apache.hadoop.hbase.util.ServerCommandLine;
42  import org.apache.hadoop.hbase.zookeeper.MiniZooKeeperCluster;
43  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
44  import org.apache.zookeeper.KeeperException;
45  
46  @InterfaceAudience.Private
47  public class HMasterCommandLine extends ServerCommandLine {
48    private static final Log LOG = LogFactory.getLog(HMasterCommandLine.class);
49  
50    private static final String USAGE =
51      "Usage: Master [opts] start|stop|clear\n" +
52      " start  Start Master. If local mode, start Master and RegionServer in same JVM\n" +
53      " stop   Start cluster shutdown; Master signals RegionServer shutdown\n" +
54      " clear  Delete the master znode in ZooKeeper after a master crashes\n "+
55      " where [opts] are:\n" +
56      "   --minServers=<servers>    Minimum RegionServers needed to host user tables.\n" +
57      "   --backup                  Master should start in backup mode";
58  
59    private final Class<? extends HMaster> masterClass;
60  
61    public HMasterCommandLine(Class<? extends HMaster> masterClass) {
62      this.masterClass = masterClass;
63    }
64  
65    protected String getUsage() {
66      return USAGE;
67    }
68  
69  
70    public int run(String args[]) throws Exception {
71      Options opt = new Options();
72      opt.addOption("minServers", true, "Minimum RegionServers needed to host user tables");
73      opt.addOption("backup", false, "Do not try to become HMaster until the primary fails");
74  
75  
76      CommandLine cmd;
77      try {
78        cmd = new GnuParser().parse(opt, args);
79      } catch (ParseException e) {
80        LOG.error("Could not parse: ", e);
81        usage(null);
82        return -1;
83      }
84  
85  
86      if (cmd.hasOption("minServers")) {
87        String val = cmd.getOptionValue("minServers");
88        getConf().setInt("hbase.regions.server.count.min",
89                    Integer.valueOf(val));
90        LOG.debug("minServers set to " + val);
91      }
92  
93      // check if we are the backup master - override the conf if so
94      if (cmd.hasOption("backup")) {
95        getConf().setBoolean(HConstants.MASTER_TYPE_BACKUP, true);
96      }
97  
98      List<String> remainingArgs = cmd.getArgList();
99      if (remainingArgs.size() != 1) {
100       usage(null);
101       return -1;
102     }
103 
104     String command = remainingArgs.get(0);
105 
106     if ("start".equals(command)) {
107       return startMaster();
108     } else if ("stop".equals(command)) {
109       return stopMaster();
110     } else if ("clear".equals(command)) {
111       return (ZNodeClearer.clear(getConf()) ? 0 : -1);
112     } else {
113       usage("Invalid command: " + command);
114       return -1;
115     }
116   }
117 
118   private int startMaster() {
119     Configuration conf = getConf();
120     try {
121       // If 'local', defer to LocalHBaseCluster instance.  Starts master
122       // and regionserver both in the one JVM.
123       if (LocalHBaseCluster.isLocal(conf)) {
124         final MiniZooKeeperCluster zooKeeperCluster = new MiniZooKeeperCluster(conf);
125         File zkDataPath = new File(conf.get(HConstants.ZOOKEEPER_DATA_DIR));
126         int zkClientPort = conf.getInt(HConstants.ZOOKEEPER_CLIENT_PORT, 0);
127         if (zkClientPort == 0) {
128           throw new IOException("No config value for "
129               + HConstants.ZOOKEEPER_CLIENT_PORT);
130         }
131         zooKeeperCluster.setDefaultClientPort(zkClientPort);
132 
133         // login the zookeeper server principal (if using security)
134         ZKUtil.loginServer(conf, "hbase.zookeeper.server.keytab.file",
135           "hbase.zookeeper.server.kerberos.principal", null);
136 
137         int clientPort = zooKeeperCluster.startup(zkDataPath);
138         if (clientPort != zkClientPort) {
139           String errorMsg = "Could not start ZK at requested port of " +
140             zkClientPort + ".  ZK was started at port: " + clientPort +
141             ".  Aborting as clients (e.g. shell) will not be able to find " +
142             "this ZK quorum.";
143           System.err.println(errorMsg);
144           throw new IOException(errorMsg);
145         }
146         conf.set(HConstants.ZOOKEEPER_CLIENT_PORT,
147                  Integer.toString(clientPort));
148         // Need to have the zk cluster shutdown when master is shutdown.
149         // Run a subclass that does the zk cluster shutdown on its way out.
150         LocalHBaseCluster cluster = new LocalHBaseCluster(conf, 1, 1,
151                                                           LocalHMaster.class, HRegionServer.class);
152         ((LocalHMaster)cluster.getMaster(0)).setZKCluster(zooKeeperCluster);
153         cluster.startup();
154         waitOnMasterThreads(cluster);
155       } else {
156         HMaster master = HMaster.constructMaster(masterClass, conf);
157         if (master.isStopped()) {
158           LOG.info("Won't bring the Master up as a shutdown is requested");
159           return -1;
160         }
161         master.start();
162         master.join();
163         if(master.isAborted())
164           throw new RuntimeException("HMaster Aborted");
165       }
166     } catch (Throwable t) {
167       LOG.error("Failed to start master", t);
168       return -1;
169     }
170     return 0;
171   }
172 
173   private int stopMaster() {
174     HBaseAdmin adm = null;
175     try {
176       Configuration conf = getConf();
177       // Don't try more than once
178       conf.setInt("hbase.client.retries.number", 1);
179       adm = new HBaseAdmin(getConf());
180     } catch (MasterNotRunningException e) {
181       LOG.error("Master not running");
182       return -1;
183     } catch (ZooKeeperConnectionException e) {
184       LOG.error("ZooKeeper not available");
185       return -1;
186     } catch (IOException e) {
187       LOG.error("Got IOException: " +e.getMessage(), e);
188       return -1;
189     }
190     try {
191       adm.shutdown();
192     } catch (Throwable t) {
193       LOG.error("Failed to stop master", t);
194       return -1;
195     }
196     return 0;
197   }
198 
199   private void waitOnMasterThreads(LocalHBaseCluster cluster) throws InterruptedException{
200     List<JVMClusterUtil.MasterThread> masters = cluster.getMasters();
201     List<JVMClusterUtil.RegionServerThread> regionservers = cluster.getRegionServers();
202 	  
203     if (masters != null) { 
204       for (JVMClusterUtil.MasterThread t : masters) {
205         t.join();
206         if(t.getMaster().isAborted()) {
207           closeAllRegionServerThreads(regionservers);
208           throw new RuntimeException("HMaster Aborted");
209         }
210       }
211     }
212   }
213 
214   private static void closeAllRegionServerThreads(List<JVMClusterUtil.RegionServerThread> regionservers) {
215     for(JVMClusterUtil.RegionServerThread t : regionservers){
216       t.getRegionServer().stop("HMaster Aborted; Bringing down regions servers");
217     }
218   }
219   
220   /*
221    * Version of master that will shutdown the passed zk cluster on its way out.
222    */
223   public static class LocalHMaster extends HMaster {
224     private MiniZooKeeperCluster zkcluster = null;
225 
226     public LocalHMaster(Configuration conf)
227     throws IOException, KeeperException, InterruptedException {
228       super(conf);
229     }
230 
231     @Override
232     public void run() {
233       super.run();
234       if (this.zkcluster != null) {
235         try {
236           this.zkcluster.shutdown();
237         } catch (IOException e) {
238           e.printStackTrace();
239         }
240       }
241     }
242 
243     void setZKCluster(final MiniZooKeeperCluster zkcluster) {
244       this.zkcluster = zkcluster;
245     }
246   }
247 }