View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.chaos.util;
19  
20  import java.io.IOException;
21  import java.util.Properties;
22  import java.util.Set;
23  
24  import org.apache.commons.cli.CommandLine;
25  import org.apache.commons.lang.StringUtils;
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.conf.Configuration;
29  import org.apache.hadoop.hbase.HBaseConfiguration;
30  import org.apache.hadoop.hbase.HConstants;
31  import org.apache.hadoop.hbase.IntegrationTestingUtility;
32  import org.apache.hadoop.hbase.TableName;
33  import org.apache.hadoop.hbase.chaos.factories.MonkeyFactory;
34  import org.apache.hadoop.hbase.chaos.monkies.ChaosMonkey;
35  import org.apache.hadoop.hbase.util.AbstractHBaseTool;
36  import org.apache.hadoop.util.ToolRunner;
37  
38  import com.google.common.collect.Sets;
39  
40  public class ChaosMonkeyRunner extends AbstractHBaseTool {
41    private static final Log LOG = LogFactory.getLog(ChaosMonkeyRunner.class);
42  
43    public static final String MONKEY_LONG_OPT = "monkey";
44    public static final String CHAOS_MONKEY_PROPS = "monkeyProps";
45    public static final String TABLE_NAME_OPT = "tableName";
46    public static final String FAMILY_NAME_OPT = "familyName";
47  
48    private static ChaosMonkeyRunner runner;
49  
50    protected IntegrationTestingUtility util;
51    protected ChaosMonkey monkey;
52    protected String monkeyToUse;
53    protected Properties monkeyProps;
54    protected boolean noClusterCleanUp = false;
55    private String tableName = "ChaosMonkeyRunner.tableName";
56    private String familyName = "ChaosMonkeyRunner.familyName";
57    private volatile boolean stop = false;
58  
59    @Override
60    public void addOptions() {
61      addOptWithArg("m", MONKEY_LONG_OPT, "Which chaos monkey to run");
62      addOptWithArg(CHAOS_MONKEY_PROPS, "The properties file for specifying chaos "
63          + "monkey properties.");
64      addOptWithArg(TABLE_NAME_OPT, "Table name in the test to run chaos monkey against");
65      addOptWithArg(FAMILY_NAME_OPT, "Family name in the test to run chaos monkey against");
66    }
67  
68    @Override
69    protected void processOptions(CommandLine cmd) {
70      if (cmd.hasOption(MONKEY_LONG_OPT)) {
71        monkeyToUse = cmd.getOptionValue(MONKEY_LONG_OPT);
72      }
73      monkeyProps = new Properties();
74      if (cmd.hasOption(CHAOS_MONKEY_PROPS)) {
75        String chaosMonkeyPropsFile = cmd.getOptionValue(CHAOS_MONKEY_PROPS);
76        if (StringUtils.isNotEmpty(chaosMonkeyPropsFile)) {
77          try {
78            monkeyProps.load(this.getClass().getClassLoader()
79                .getResourceAsStream(chaosMonkeyPropsFile));
80          } catch (IOException e) {
81            LOG.warn(e);
82            System.exit(EXIT_FAILURE);
83          }
84        }
85      }
86      if (cmd.hasOption(TABLE_NAME_OPT)) {
87        this.tableName = cmd.getOptionValue(TABLE_NAME_OPT);
88      }
89      if (cmd.hasOption(FAMILY_NAME_OPT)) {
90        this.familyName = cmd.getOptionValue(FAMILY_NAME_OPT);
91      }
92    }
93  
94    @Override
95    protected int doWork() throws Exception {
96      setUpCluster();
97      getAndStartMonkey();
98      while (!stop) {// loop here until got killed
99        Thread.sleep(10000);
100     }
101     return 0;
102   }
103 
104   public static void stopRunner() {
105     runner.stop = true;
106   }
107 
108   public void setUpCluster() throws Exception {
109     util = getTestingUtil(getConf());
110     boolean isDistributed = isDistributedCluster(getConf());
111     if (isDistributed) {
112       util.createDistributedHBaseCluster();
113       util.checkNodeCount(1);// make sure there's at least 1 alive rs
114     } else {
115       throw new RuntimeException("ChaosMonkeyRunner must run againt a distributed cluster,"
116           + " please check and point to the right configuration dir");
117     }
118     this.setConf(util.getConfiguration());
119   }
120 
121   private boolean isDistributedCluster(Configuration conf) {
122     return conf.getBoolean(HConstants.CLUSTER_DISTRIBUTED, false);
123   }
124 
125   public void getAndStartMonkey() throws Exception {
126     util = getTestingUtil(getConf());
127     MonkeyFactory fact = MonkeyFactory.getFactory(monkeyToUse);
128     if (fact == null) {
129       fact = getDefaultMonkeyFactory();
130     }
131     monkey =
132         fact.setUtil(util).setTableName(getTablename()).setProperties(monkeyProps)
133             .setColumnFamilies(getColumnFamilies()).build();
134     monkey.start();
135   }
136 
137   protected IntegrationTestingUtility getTestingUtil(Configuration conf) {
138     if (this.util == null) {
139       if (conf == null) {
140         this.util = new IntegrationTestingUtility();
141         this.setConf(util.getConfiguration());
142       } else {
143         this.util = new IntegrationTestingUtility(conf);
144       }
145     }
146     return util;
147   }
148 
149   protected MonkeyFactory getDefaultMonkeyFactory() {
150     // Run with slow deterministic monkey by default
151     return MonkeyFactory.getFactory(MonkeyFactory.SLOW_DETERMINISTIC);
152   }
153 
154   public TableName getTablename() {
155     return TableName.valueOf(tableName);
156   }
157 
158   protected Set<String> getColumnFamilies() {
159     return Sets.newHashSet(familyName);
160   }
161 
162   /*
163    * If caller wants to add config parameters contained in a file, the path of conf file
164    * can be passed as the first two arguments like this:
165    *   -c <path-to-conf>
166    */
167   public static void main(String[] args) throws Exception {
168     Configuration conf = HBaseConfiguration.create();
169     String[] actualArgs = args;
170     if (args.length > 0 && "-c".equals(args[0])) {
171       int argCount = args.length - 2;
172       if (argCount < 0) {
173         throw new IllegalArgumentException("Missing path for -c parameter");
174       }
175       // load the resource specified by the second parameter
176       conf.addResource(args[1]);
177       actualArgs = new String[argCount];
178       System.arraycopy(args, 2, actualArgs, 0, argCount);
179     }
180     IntegrationTestingUtility.setUseDistributedCluster(conf);
181     runner = new ChaosMonkeyRunner();
182     int ret = ToolRunner.run(conf, runner, actualArgs);
183     System.exit(ret);
184   }
185 
186 }