/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.mapred;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import org.apache.hadoop.mapred.UtilsForTests;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.mapreduce.test.system.MRCluster;
import org.junit.BeforeClass;
import org.junit.Test;
import org.apache.hadoop.mapreduce.test.system.TTClient;
import org.apache.hadoop.mapreduce.test.system.JTClient;
import org.apache.hadoop.mapreduce.test.system.MRCluster.Role;
import org.apache.hadoop.util.Shell.ShellCommandExecutor;
import org.apache.hadoop.mapred.TaskTrackerStatus;
import org.apache.hadoop.test.system.process.HadoopDaemonRemoteCluster;
import org.junit.AfterClass;
import org.junit.Assert;
/**
* This is helper class that is used by the health script test cases
*
*/
public class HealthScriptHelper {
static final Log LOG = LogFactory.getLog(HealthScriptHelper.class);
/**
* Will verify that given task tracker is not blacklisted
* @param client tasktracker info
* @param conf modified configuration object
* @param cluster mrcluster instance
* @throws IOException thrown if verification fails
*/
public void verifyTTNotBlackListed(TTClient client, Configuration conf,
MRCluster cluster) throws IOException {
int interval = conf.getInt("mapred.healthChecker.interval",0);
Assert.assertTrue("Interval cannot be zero.",interval != 0);
UtilsForTests.waitFor(interval+2000);
String defaultHealthScript = conf.get("mapred.healthChecker.script.path");
Assert.assertTrue("Task tracker is not healthy",
nodeHealthStatus(client, true) == true);
TaskTrackerStatus status = client.getStatus();
JTClient jclient = cluster.getJTClient();
Assert.assertTrue("Failed to move task tracker to healthy list",
jclient.getProxy().isBlackListed(status.getTrackerName()) == false);
Assert.assertTrue("Health script was not set",defaultHealthScript != null);
}
/**
* Verifies that the given task tracker is blacklisted
* @param conf modified Configuration object
* @param client tasktracker info
* @param errorMessage that needs to be asserted
* @param cluster mr cluster instance
* @throws IOException is thrown when verification fails
*/
public void verifyTTBlackList(Configuration conf, TTClient client,
String errorMessage, MRCluster cluster) throws IOException{
int interval = conf.getInt("mapred.healthChecker.interval",0);
Assert.assertTrue("Interval cannot be zero.",interval != 0);
UtilsForTests.waitFor(interval+2000);
//TaskTrackerStatus status = client.getStatus();
Assert.assertTrue("Task tracker was never blacklisted ",
nodeHealthStatus(client, false) == true);
TaskTrackerStatus status = client.getStatus();
Assert.assertTrue("The custom error message did not appear",
status.getHealthStatus().getHealthReport().trim().
equals(errorMessage));
JTClient jClient = cluster.getJTClient();
Assert.assertTrue("Failed to move task tracker to blacklisted list",
jClient.getProxy().isBlackListed(status.getTrackerName()) == true);
}
/**
* The method return true from the task tracker if it is unhealthy/healthy
* depending the blacklisted status
* @param client the tracker tracker instance
* @param health status information.
* @return status of task tracker
* @throws IOException failed to get the status of task tracker
*/
public boolean nodeHealthStatus(TTClient client,boolean hStatus) throws IOException {
int counter = 0;
TaskTrackerStatus status = client.getStatus();
while (counter < 60) {
LOG.info("isNodeHealthy "+status.getHealthStatus().isNodeHealthy());
if (status.getHealthStatus().isNodeHealthy() == hStatus) {
break;
} else {
UtilsForTests.waitFor(3000);
status = client.getStatus();
Assert.assertNotNull("Task tracker status is null",status);
}
counter++;
}
if(counter != 60) {
return true;
}
return false;
}
/**
* This will copy the error inducing health script from local node running
* the system tests to the node where the task tracker runs
* @param scriptName name of the scirpt to be copied
* @param hostname identifies the task tracker
* @param remoteLocation location in remote task tracker node
* @param cluster mrcluster instance
* @throws IOException thrown if copy file fails.
*/
public void copyFileToRemoteHost(String scriptName, String hostname,
String remoteLocation,MRCluster cluster) throws IOException {
ArrayList<String> cmdArgs = new ArrayList<String>();
String scriptDir = cluster.getConf().get(
HadoopDaemonRemoteCluster.CONF_SCRIPTDIR);
StringBuffer localFile = new StringBuffer();
localFile.append(scriptDir).append(File.separator).append(scriptName);
cmdArgs.add("scp");
cmdArgs.add(localFile.toString());
StringBuffer remoteFile = new StringBuffer();
remoteFile.append(hostname).append(":");
remoteFile.append(remoteLocation).append(File.separator).append(scriptName);
cmdArgs.add(remoteFile.toString());
executeCommand(cmdArgs);
}
private void executeCommand(ArrayList<String> cmdArgs) throws IOException{
String[] cmd = (String[]) cmdArgs.toArray(new String[cmdArgs.size()]);
ShellCommandExecutor executor = new ShellCommandExecutor(cmd);
LOG.info(executor.toString());
executor.execute();
String output = executor.getOutput();
if (!output.isEmpty()) { //getOutput() never returns null value
if (output.toLowerCase().contains("error")) {
LOG.warn("Error is detected.");
throw new IOException("Start error\n" + output);
}
}
}
/**
* cleans up the error inducing health script in the remote node
* @param path the script that needs to be deleted
* @param hostname where the script resides.
*/
public void deleteFileOnRemoteHost(String path, String hostname) {
try {
ArrayList<String> cmdArgs = new ArrayList<String>();
cmdArgs.add("ssh");
cmdArgs.add(hostname);
cmdArgs.add("if [ -f "+ path+
" ];\n then echo Will remove existing file "+path+"; rm -f "+
path+";\n fi");
executeCommand(cmdArgs);
}
catch (IOException io) {
LOG.error("Failed to remove the script "+path+" on remote host "+hostname);
}
}
}