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