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