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;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertFalse;
22  import static org.junit.Assert.assertTrue;
23  
24  import java.io.File;
25  import java.io.FileOutputStream;
26  import java.io.IOException;
27  import java.io.PrintWriter;
28  import java.util.UUID;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.hadoop.conf.Configuration;
33  import org.apache.hadoop.fs.FileSystem;
34  import org.apache.hadoop.fs.Path;
35  import org.apache.hadoop.hbase.HealthChecker.HealthCheckerExitStatus;
36  import org.apache.hadoop.hbase.testclassification.SmallTests;
37  import org.apache.hadoop.util.Shell;
38  import org.junit.After;
39  import org.junit.Test;
40  import org.junit.experimental.categories.Category;
41  
42  @Category(SmallTests.class)
43  public class TestNodeHealthCheckChore {
44  
45    private static final Log LOG = LogFactory.getLog(TestNodeHealthCheckChore.class);
46    private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
47    private static final int SCRIPT_TIMEOUT = 5000;
48    private File healthScriptFile;
49    private String eol = System.getProperty("line.separator");
50  
51    @After
52    public void cleanUp() throws IOException {
53      // delete and recreate the test directory, ensuring a clean test dir between tests
54      Path testDir = UTIL.getDataTestDir();
55      FileSystem fs = UTIL.getTestFileSystem();
56      fs.delete(testDir, true);
57      if (!fs.mkdirs(testDir)) throw new IOException("Failed mkdir " + testDir);
58    }
59  
60    @Test(timeout=60000)
61    public void testHealthCheckerSuccess() throws Exception {
62      String normalScript = "echo \"I am all fine\"";
63      healthCheckerTest(normalScript, HealthCheckerExitStatus.SUCCESS);
64    }
65  
66    @Test(timeout=60000)
67    public void testHealthCheckerFail() throws Exception {
68      String errorScript = "echo ERROR" + eol + "echo \"Node not healthy\"";
69      healthCheckerTest(errorScript, HealthCheckerExitStatus.FAILED);
70    }
71  
72    @Test(timeout=60000)
73    public void testHealthCheckerTimeout() throws Exception {
74      String timeOutScript = "sleep 10" + eol + "echo \"I am fine\"";
75      healthCheckerTest(timeOutScript, HealthCheckerExitStatus.TIMED_OUT);
76    }
77  
78    public void healthCheckerTest(String script, HealthCheckerExitStatus expectedStatus)
79        throws Exception {
80      Configuration config = getConfForNodeHealthScript();
81      config.addResource(healthScriptFile.getName());
82      String location = healthScriptFile.getAbsolutePath();
83      long timeout = config.getLong(HConstants.HEALTH_SCRIPT_TIMEOUT, SCRIPT_TIMEOUT);
84  
85      HealthChecker checker = new HealthChecker();
86      checker.init(location, timeout);
87  
88      createScript(script, true);
89      HealthReport report = checker.checkHealth();
90      assertEquals(expectedStatus, report.getStatus());
91  
92      LOG.info("Health Status:" + report.getHealthReport());
93  
94      this.healthScriptFile.delete();
95    }
96  
97    @Test(timeout=60000)
98    public void testRSHealthChore() throws Exception{
99      Stoppable stop = new StoppableImplementation();
100     Configuration conf = getConfForNodeHealthScript();
101     String errorScript = "echo ERROR" + eol + " echo \"Server not healthy\"";
102     createScript(errorScript, true);
103     HealthCheckChore rsChore = new HealthCheckChore(100, stop, conf);
104     try {
105       //Default threshold is three.
106       rsChore.chore();
107       rsChore.chore();
108       assertFalse("Stoppable must not be stopped.", stop.isStopped());
109       rsChore.chore();
110       assertTrue("Stoppable must have been stopped.", stop.isStopped());
111     } finally {
112       stop.stop("Finished w/ test");
113     }
114   }
115 
116   private void createScript(String scriptStr, boolean setExecutable)
117       throws Exception {
118     if (!this.healthScriptFile.exists()) {
119       if (!healthScriptFile.createNewFile()) {
120         throw new IOException("Failed create of " + this.healthScriptFile);
121       }
122     }
123     PrintWriter pw = new PrintWriter(new FileOutputStream(healthScriptFile));
124     try {
125       pw.println(scriptStr);
126       pw.flush();
127     } finally {
128       pw.close();
129     }
130     healthScriptFile.setExecutable(setExecutable);
131     LOG.info("Created " + this.healthScriptFile + ", executable=" + setExecutable);
132   }
133 
134   private Configuration getConfForNodeHealthScript() throws IOException {
135     Configuration conf = UTIL.getConfiguration();
136     File tempDir = new File(UTIL.getDataTestDir().toString());
137     if (!tempDir.exists()) {
138       if (!tempDir.mkdirs()) {
139         throw new IOException("Failed mkdirs " + tempDir);
140       }
141     }
142     String scriptName = "HealthScript" + UUID.randomUUID().toString()
143         + (Shell.WINDOWS ? ".cmd" : ".sh");
144     healthScriptFile = new File(tempDir.getAbsolutePath(), scriptName);
145     conf.set(HConstants.HEALTH_SCRIPT_LOC, healthScriptFile.getAbsolutePath());
146     conf.setLong(HConstants.HEALTH_FAILURE_THRESHOLD, 3);
147     conf.setLong(HConstants.HEALTH_SCRIPT_TIMEOUT, SCRIPT_TIMEOUT);
148     return conf;
149   }
150 
151   /**
152    * Simple helper class that just keeps track of whether or not its stopped.
153    */
154   private static class StoppableImplementation implements Stoppable {
155     private volatile boolean stop = false;
156 
157     @Override
158     public void stop(String why) {
159       this.stop = true;
160     }
161 
162     @Override
163     public boolean isStopped() {
164       return this.stop;
165     }
166 
167   }
168 }