You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by co...@apache.org on 2010/05/15 01:56:35 UTC

svn commit: r944521 [3/3] - in /hadoop/common/trunk: ./ ivy/ src/test/ src/test/aop/build/ src/test/system/ src/test/system/aop/ src/test/system/aop/org/ src/test/system/aop/org/apache/ src/test/system/aop/org/apache/hadoop/ src/test/system/aop/org/apa...

Added: hadoop/common/trunk/src/test/system/c++/runAs/configure.ac
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/c%2B%2B/runAs/configure.ac?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/c++/runAs/configure.ac (added)
+++ hadoop/common/trunk/src/test/system/c++/runAs/configure.ac Fri May 14 23:56:34 2010
@@ -0,0 +1,65 @@
+#                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
+
+AC_PREREQ(2.59)
+AC_INIT([runAs],[0.1])
+
+#changing default prefix value to empty string, so that binary does not
+#gets installed within system
+AC_PREFIX_DEFAULT(.)
+
+#add new arguments --with-home
+AC_ARG_WITH(home,[--with-home path to hadoop home dir])
+AC_CONFIG_SRCDIR([main.c])
+AC_CONFIG_HEADER([runAs.h])
+
+# Checks for programs.
+AC_PROG_CC
+
+# Checks for libraries.
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS([stdlib.h string.h unistd.h fcntl.h])
+
+#check for HADOOP_HOME
+if test "$with_home" != ""
+then
+AC_DEFINE_UNQUOTED(HADOOP_HOME,"$with_home")
+fi
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_PID_T
+AC_TYPE_MODE_T
+AC_TYPE_SIZE_T
+
+# Checks for library functions.
+AC_FUNC_MALLOC
+AC_FUNC_REALLOC
+AC_FUNC_CHOWN
+AC_CHECK_FUNCS([strerror memset mkdir rmdir strdup])
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
+
+AC_HEADER_STDBOOL
+AC_PROG_MAKE_SET

Added: hadoop/common/trunk/src/test/system/c++/runAs/main.c
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/c%2B%2B/runAs/main.c?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/c++/runAs/main.c (added)
+++ hadoop/common/trunk/src/test/system/c++/runAs/main.c Fri May 14 23:56:34 2010
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+#include "runAs.h"
+
+/**
+ * The binary would be accepting the command of following format:
+ * cluster-controller user hostname hadoop-daemon.sh-command
+ */
+int main(int argc, char **argv) {
+  int errorcode;
+  char *user;
+  char *hostname;
+  char *command;
+  struct passwd user_detail;
+  int i = 1;
+  /*
+   * Minimum number of arguments required for the binary to perform.
+   */
+  if (argc < 4) {
+    fprintf(stderr, "Invalid number of arguments passed to the binary\n");
+    return INVALID_ARGUMENT_NUMER;
+  }
+
+  user = argv[1];
+  if (user == NULL) {
+    fprintf(stderr, "Invalid user name\n");
+    return INVALID_USER_NAME;
+  }
+
+  if (getuserdetail(user, &user_detail) != 0) {
+    fprintf(stderr, "Invalid user name\n");
+    return INVALID_USER_NAME;
+  }
+
+  if (user_detail.pw_gid == 0 || user_detail.pw_uid == 0) {
+      fprintf(stderr, "Cannot run tasks as super user\n");
+      return SUPER_USER_NOT_ALLOWED_TO_RUN_COMMANDS;
+  }
+
+  hostname = argv[2];
+  command = argv[3];
+  return process_controller_command(user, hostname, command);
+}

Added: hadoop/common/trunk/src/test/system/c++/runAs/runAs.c
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/c%2B%2B/runAs/runAs.c?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/c++/runAs/runAs.c (added)
+++ hadoop/common/trunk/src/test/system/c++/runAs/runAs.c Fri May 14 23:56:34 2010
@@ -0,0 +1,111 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+#include "runAs.h"
+
+/*
+ * Function to get the user details populated given a user name. 
+ */
+int getuserdetail(char *user, struct passwd *user_detail) {
+  struct passwd *tempPwdPtr;
+  int size = sysconf(_SC_GETPW_R_SIZE_MAX);
+  char pwdbuffer[size];
+  if ((getpwnam_r(user, user_detail, pwdbuffer, size, &tempPwdPtr)) != 0) {
+    fprintf(stderr, "Invalid user provided to getpwnam\n");
+    return -1;
+  }
+  return 0;
+}
+
+/**
+ * Function to switch the user identity and set the appropriate 
+ * group control as the user specified in the argument.
+ */
+int switchuser(char *user) {
+  //populate the user details
+  struct passwd user_detail;
+  if ((getuserdetail(user, &user_detail)) != 0) {
+    return INVALID_USER_NAME;
+  }
+  //set the right supplementary groups for the user.
+  if (initgroups(user_detail.pw_name, user_detail.pw_gid) != 0) {
+    fprintf(stderr, "Init groups call for the user : %s failed\n",
+        user_detail.pw_name);
+    return INITGROUPS_FAILED;
+  }
+  errno = 0;
+  //switch the group.
+  setgid(user_detail.pw_gid);
+  if (errno != 0) {
+    fprintf(stderr, "Setgid for the user : %s failed\n", user_detail.pw_name);
+    return SETUID_OPER_FAILED;
+  }
+  errno = 0;
+  //swith the user
+  setuid(user_detail.pw_uid);
+  if (errno != 0) {
+    fprintf(stderr, "Setuid for the user : %s failed\n", user_detail.pw_name);
+    return SETUID_OPER_FAILED;
+  }
+  errno = 0;
+  //set the effective user id.
+  seteuid(user_detail.pw_uid);
+  if (errno != 0) {
+    fprintf(stderr, "Seteuid for the user : %s failed\n", user_detail.pw_name);
+    return SETUID_OPER_FAILED;
+  }
+  return 0;
+}
+
+/*
+ * Top level method which processes a cluster management
+ * command.
+ */
+int process_cluster_command(char * user,  char * node , char *command) {
+  char *finalcommandstr;
+  int len;
+  int errorcode = 0;
+  if (strncmp(command, "", strlen(command)) == 0) {
+    fprintf(stderr, "Invalid command passed\n");
+    return INVALID_COMMAND_PASSED;
+  }
+  len = STRLEN + strlen(command);
+  finalcommandstr = (char *) malloc((len + 1) * sizeof(char));
+  snprintf(finalcommandstr, len, SCRIPT_DIR_PATTERN, HADOOP_HOME,
+      command);
+  finalcommandstr[len + 1] = '\0';
+  errorcode = switchuser(user);
+  if (errorcode != 0) {
+    fprintf(stderr, "switch user failed\n");
+    return errorcode;
+  }
+  errno = 0;
+  execlp(SSH_COMMAND, SSH_COMMAND, node, finalcommandstr, NULL);
+  if (errno != 0) {
+    fprintf(stderr, "Excelp failed dude to : %s\n", strerror(errno));
+  }
+  return 0;
+}
+
+/*
+ * Process cluster controller command the API exposed to the 
+ * main in order to execute the cluster commands.
+ */
+int process_controller_command(char *user, char * node, char *command) {
+  return process_cluster_command(user, node, command);
+}

Added: hadoop/common/trunk/src/test/system/c++/runAs/runAs.h.in
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/c%2B%2B/runAs/runAs.h.in?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/c++/runAs/runAs.h.in (added)
+++ hadoop/common/trunk/src/test/system/c++/runAs/runAs.h.in Fri May 14 23:56:34 2010
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <assert.h>
+#include <getopt.h>
+#include <grp.h>
+
+/*
+* List of possible error codes.
+*/
+enum errorcodes {
+  INVALID_ARGUMENT_NUMER = 1,
+  INVALID_USER_NAME, //2
+  SUPER_USER_NOT_ALLOWED_TO_RUN_COMMANDS, //3
+  INITGROUPS_FAILED, //4
+  SETUID_OPER_FAILED, //5
+  INVALID_COMMAND_PASSED, //6
+};
+
+#undef HADOOP_HOME
+
+#define SSH_COMMAND "ssh"
+
+#define SCRIPT_DIR_PATTERN "%s/bin/hadoop-daemon.sh %s" //%s to be substituded 
+
+#define STRLEN strlen(SCRIPT_DIR_PATTERN) + strlen(HADOOP_HOME)
+
+/*
+ * Function to get the user details populated given a user name. 
+ */
+int getuserdetails(char *user, struct passwd *user_detail);
+
+ /*
+ * Process cluster controller command the API exposed to the 
+ * main in order to execute the cluster commands.
+ */
+int process_controller_command(char *user, char *node, char *command);

Added: hadoop/common/trunk/src/test/system/conf/hadoop-policy-system-test.xml
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/conf/hadoop-policy-system-test.xml?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/conf/hadoop-policy-system-test.xml (added)
+++ hadoop/common/trunk/src/test/system/conf/hadoop-policy-system-test.xml Fri May 14 23:56:34 2010
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+
+<configuration>
+<!--
+  This is Herriot specific protocols. This section shouldn't be present in
+  a production cluster configuration. This file needs to be linked up to the
+  main conf/hadoop-policy.xml in the deployment process
+-->
+  <property>
+    <name>security.daemon.protocol.acl</name>
+    <value>*</value>
+    <description>ACL for DaemonProtocol, extended by all other
+    Herriot RPC protocols.
+    The ACL is a comma-separated list of user and group names. The user and
+    group list is separated by a blank. For e.g. "alice,bob users,wheel".
+    A special value of "*" means all users are allowed.</description>
+  </property>
+
+  <property>
+    <name>security.nn.protocol.acl</name>
+    <value>*</value>
+    <description>ACL for NNProtocol, used by the
+    Herriot AbstractDaemonCluster's implementations to connect to a remote
+    NameNode.
+    The ACL is a comma-separated list of user and group names. The user and
+    group list is separated by a blank. For e.g. "alice,bob users,wheel".
+    A special value of "*" means all users are allowed.</description>
+  </property>
+
+  <property>
+    <name>security.dn.protocol.acl</name>
+    <value>*</value>
+    <description>ACL for DNProtocol, used by the
+    Herriot AbstractDaemonCluster's implementations to connect to a remote
+    DataNode.
+    The ACL is a comma-separated list of user and group names. The user and
+    group list is separated by a blank. For e.g. "alice,bob users,wheel".
+    A special value of "*" means all users are allowed.</description>
+  </property>
+
+  <property>
+    <name>security.tt.protocol.acl</name>
+    <value>*</value>
+    <description>ACL for TTProtocol, used by the
+    Herriot AbstractDaemonCluster's implementations to connect to a remote
+    TaskTracker.
+    The ACL is a comma-separated list of user and group names. The user and
+    group list is separated by a blank. For e.g. "alice,bob users,wheel".
+    A special value of "*" means all users are allowed.</description>
+  </property>
+</configuration>

Added: hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/AbstractDaemonClient.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/AbstractDaemonClient.java?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/AbstractDaemonClient.java (added)
+++ hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/AbstractDaemonClient.java Fri May 14 23:56:34 2010
@@ -0,0 +1,343 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.test.system;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+import java.util.List;
+import org.junit.Assert;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.test.system.process.RemoteProcess;
+/**
+ * Abstract class which encapsulates the DaemonClient which is used in the 
+ * system tests.<br/>
+ * 
+ * @param PROXY the proxy implementation of a specific Daemon 
+ */
+public abstract class AbstractDaemonClient<PROXY extends DaemonProtocol> {
+  private Configuration conf;
+  private RemoteProcess process;
+  private boolean connected;
+
+  private static final Log LOG = LogFactory.getLog(AbstractDaemonClient.class);
+  
+  /**
+   * Create a Daemon client.<br/>
+   * 
+   * @param conf client to be used by proxy to connect to Daemon.
+   * @param process the Daemon process to manage the particular daemon.
+   * 
+   * @throws IOException
+   */
+  public AbstractDaemonClient(Configuration conf, RemoteProcess process) 
+      throws IOException {
+    this.conf = conf;
+    this.process = process;
+  }
+
+  /**
+   * Gets if the client is connected to the Daemon <br/>
+   * 
+   * @return true if connected.
+   */
+  public boolean isConnected() {
+    return connected;
+  }
+
+  protected void setConnected(boolean connected) {
+    this.connected = connected;
+  }
+
+  /**
+   * Create an RPC proxy to the daemon <br/>
+   * 
+   * @throws IOException
+   */
+  public abstract void connect() throws IOException;
+
+  /**
+   * Disconnect the underlying RPC proxy to the daemon.<br/>
+   * @throws IOException
+   */
+  public abstract void disconnect() throws IOException;
+
+  /**
+   * Get the proxy to connect to a particular service Daemon.<br/>
+   * 
+   * @return proxy to connect to a particular service Daemon.
+   */
+  protected abstract PROXY getProxy();
+
+  /**
+   * Gets the daemon level configuration.<br/>
+   * 
+   * @return configuration using which daemon is running
+   */
+  public Configuration getConf() {
+    return conf;
+  }
+
+  /**
+   * Gets the host on which Daemon is currently running. <br/>
+   * 
+   * @return hostname
+   */
+  public String getHostName() {
+    return process.getHostName();
+  }
+
+  /**
+   * Gets if the Daemon is ready to accept RPC connections. <br/>
+   * 
+   * @return true if daemon is ready.
+   * @throws IOException
+   */
+  public boolean isReady() throws IOException {
+    return getProxy().isReady();
+  }
+
+  /**
+   * Kills the Daemon process <br/>
+   * @throws IOException
+   */
+  public void kill() throws IOException {
+    process.kill();
+  }
+
+  /**
+   * Checks if the Daemon process is alive or not <br/>
+   * 
+   * @throws IOException
+   */
+  public void ping() throws IOException {
+    getProxy().ping();
+  }
+
+  /**
+   * Start up the Daemon process. <br/>
+   * @throws IOException
+   */
+  public void start() throws IOException {
+    process.start();
+  }
+
+  /**
+   * Get system level view of the Daemon process.
+   * 
+   * @return returns system level view of the Daemon process.
+   * 
+   * @throws IOException
+   */
+  public ProcessInfo getProcessInfo() throws IOException {
+    return getProxy().getProcessInfo();
+  }
+
+  /**
+   * Return a file status object that represents the path.
+   * @param path
+   *          given path
+   * @param local
+   *          whether the path is local or not
+   * @return a FileStatus object
+   * @throws java.io.FileNotFoundException when the path does not exist;
+   *         IOException see specific implementation
+   */
+  public FileStatus getFileStatus(String path, boolean local) throws IOException {
+    return getProxy().getFileStatus(path, local);
+  }
+
+  /**
+   * List the statuses of the files/directories in the given path if the path is
+   * a directory.
+   * 
+   * @param path
+   *          given path
+   * @param local
+   *          whether the path is local or not
+   * @return the statuses of the files/directories in the given patch
+   * @throws IOException
+   */
+  public FileStatus[] listStatus(String path, boolean local) 
+    throws IOException {
+    return getProxy().listStatus(path, local);
+  }
+
+  /**
+   * List the statuses of the files/directories in the given path if the path is
+   * a directory recursive/nonrecursively depending on parameters
+   * 
+   * @param path
+   *          given path
+   * @param local
+   *          whether the path is local or not
+   * @param recursive 
+   *          whether to recursively get the status
+   * @return the statuses of the files/directories in the given patch
+   * @throws IOException
+   */
+  public FileStatus[] listStatus(String path, boolean local, boolean recursive)
+    throws IOException {
+    List<FileStatus> status = new ArrayList<FileStatus>();
+    addStatus(status, path, local, recursive);
+    return status.toArray(new FileStatus[0]);
+  }
+
+  private void addStatus(List<FileStatus> status, String f, 
+      boolean local, boolean recursive) 
+    throws IOException {
+    FileStatus[] fs = listStatus(f, local);
+    if (fs != null) {
+      for (FileStatus fileStatus : fs) {
+        if (!f.equals(fileStatus.getPath().toString())) {
+          status.add(fileStatus);
+          if (recursive) {
+            addStatus(status, fileStatus.getPath().toString(), local, recursive);
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Gets number of times FATAL log messages where logged in Daemon logs. 
+   * <br/>
+   * Pattern used for searching is FATAL. <br/>
+   * @param excludeExpList list of exception to exclude 
+   * @return number of occurrence of fatal message.
+   * @throws IOException
+   */
+  public int getNumberOfFatalStatementsInLog(String [] excludeExpList)
+      throws IOException {
+    DaemonProtocol proxy = getProxy();
+    String pattern = "FATAL";
+    return proxy.getNumberOfMatchesInLogFile(pattern, excludeExpList);
+  }
+
+  /**
+   * Gets number of times ERROR log messages where logged in Daemon logs. 
+   * <br/>
+   * Pattern used for searching is ERROR. <br/>
+   * @param excludeExpList list of exception to exclude 
+   * @return number of occurrence of error message.
+   * @throws IOException
+   */
+  public int getNumberOfErrorStatementsInLog(String[] excludeExpList) 
+      throws IOException {
+    DaemonProtocol proxy = getProxy();
+    String pattern = "ERROR";    
+    return proxy.getNumberOfMatchesInLogFile(pattern, excludeExpList);
+  }
+
+  /**
+   * Gets number of times Warning log messages where logged in Daemon logs. 
+   * <br/>
+   * Pattern used for searching is WARN. <br/>
+   * @param excludeExpList list of exception to exclude 
+   * @return number of occurrence of warning message.
+   * @throws IOException
+   */
+  public int getNumberOfWarnStatementsInLog(String[] excludeExpList) 
+      throws IOException {
+    DaemonProtocol proxy = getProxy();
+    String pattern = "WARN";
+    return proxy.getNumberOfMatchesInLogFile(pattern, excludeExpList);
+  }
+
+  /**
+   * Gets number of time given Exception were present in log file. <br/>
+   * 
+   * @param e exception class.
+   * @param excludeExpList list of exceptions to exclude. 
+   * @return number of exceptions in log
+   * @throws IOException
+   */
+  public int getNumberOfExceptionsInLog(Exception e,
+      String[] excludeExpList) throws IOException {
+    DaemonProtocol proxy = getProxy();
+    String pattern = e.getClass().getSimpleName();    
+    return proxy.getNumberOfMatchesInLogFile(pattern, excludeExpList);
+  }
+
+  /**
+   * Number of times ConcurrentModificationException present in log file. 
+   * <br/>
+   * @param excludeExpList list of exceptions to exclude.
+   * @return number of times exception in log file.
+   * @throws IOException
+   */
+  public int getNumberOfConcurrentModificationExceptionsInLog(
+      String[] excludeExpList) throws IOException {
+    return getNumberOfExceptionsInLog(new ConcurrentModificationException(),
+        excludeExpList);
+  }
+
+  private int errorCount;
+  private int fatalCount;
+  private int concurrentExceptionCount;
+
+  /**
+   * Populate the initial exception counts to be used to assert once a testcase
+   * is done there was no exception in the daemon when testcase was run.
+   * @param excludeExpList list of exceptions to exclude
+   * @throws IOException
+   */
+  protected void populateExceptionCount(String [] excludeExpList) 
+      throws IOException {
+    errorCount = getNumberOfErrorStatementsInLog(excludeExpList);
+    LOG.info("Number of error messages in logs : " + errorCount);
+    fatalCount = getNumberOfFatalStatementsInLog(excludeExpList);
+    LOG.info("Number of fatal statement in logs : " + fatalCount);
+    concurrentExceptionCount =
+        getNumberOfConcurrentModificationExceptionsInLog(excludeExpList);
+    LOG.info("Number of concurrent modification in logs : "
+        + concurrentExceptionCount);
+  }
+
+  /**
+   * Assert if the new exceptions were logged into the log file.
+   * <br/>
+   * <b><i>
+   * Pre-req for the method is that populateExceptionCount() has 
+   * to be called before calling this method.</b></i>
+   * @param excludeExpList list of exceptions to exclude
+   * @throws IOException
+   */
+  protected void assertNoExceptionsOccurred(String [] excludeExpList) 
+      throws IOException {
+    int newerrorCount = getNumberOfErrorStatementsInLog(excludeExpList);
+    LOG.info("Number of error messages while asserting :" + newerrorCount);
+    int newfatalCount = getNumberOfFatalStatementsInLog(excludeExpList);
+    LOG.info("Number of fatal messages while asserting : " + newfatalCount);
+    int newconcurrentExceptionCount =
+        getNumberOfConcurrentModificationExceptionsInLog(excludeExpList);
+    LOG.info("Number of concurrentmodification exception while asserting :"
+        + newconcurrentExceptionCount);
+    Assert.assertEquals(
+        "New Error Messages logged in the log file", errorCount, newerrorCount);
+    Assert.assertEquals(
+        "New Fatal messages logged in the log file", fatalCount, newfatalCount);
+    Assert.assertEquals(
+        "New ConcurrentModificationException in log file",
+        concurrentExceptionCount, newconcurrentExceptionCount);
+  }
+}

Added: hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/AbstractDaemonCluster.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/AbstractDaemonCluster.java?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/AbstractDaemonCluster.java (added)
+++ hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/AbstractDaemonCluster.java Fri May 14 23:56:34 2010
@@ -0,0 +1,293 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.test.system;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.test.system.process.ClusterProcessManager;
+import org.apache.hadoop.test.system.process.RemoteProcess;
+
+/**
+ * Abstract class which represent the cluster having multiple daemons.
+ */
+@SuppressWarnings("unchecked")
+public abstract class AbstractDaemonCluster {
+
+  private static final Log LOG = LogFactory.getLog(AbstractDaemonCluster.class);
+  private String [] excludeExpList ;
+  private Configuration conf;
+  protected ClusterProcessManager clusterManager;
+  private Map<Enum<?>, List<AbstractDaemonClient>> daemons = 
+    new LinkedHashMap<Enum<?>, List<AbstractDaemonClient>>();
+  
+  /**
+   * Constructor to create a cluster client.<br/>
+   * 
+   * @param conf
+   *          Configuration to be used while constructing the cluster.
+   * @param rcluster
+   *          process manger instance to be used for managing the daemons.
+   * 
+   * @throws IOException
+   */
+  public AbstractDaemonCluster(Configuration conf,
+      ClusterProcessManager rcluster) throws IOException {
+    this.conf = conf;
+    this.clusterManager = rcluster;
+    createAllClients();
+  }
+
+  /**
+   * The method returns the cluster manager. The system test cases require an
+   * instance of HadoopDaemonRemoteCluster to invoke certain operation on the
+   * daemon.
+   * 
+   * @return instance of clusterManager
+   */
+  public ClusterProcessManager getClusterManager() {
+    return clusterManager;
+  }
+
+  protected void createAllClients() throws IOException {
+    for (RemoteProcess p : clusterManager.getAllProcesses()) {
+      List<AbstractDaemonClient> dms = daemons.get(p.getRole());
+      if (dms == null) {
+        dms = new ArrayList<AbstractDaemonClient>();
+        daemons.put(p.getRole(), dms);
+      }
+      dms.add(createClient(p));
+    }
+  }
+  
+  /**
+   * Method to create the daemon client.<br/>
+   * 
+   * @param process
+   *          to manage the daemon.
+   * @return instance of the daemon client
+   * 
+   * @throws IOException
+   */
+  protected abstract AbstractDaemonClient<DaemonProtocol> 
+    createClient(RemoteProcess process) throws IOException;
+
+  /**
+   * Get the global cluster configuration which was used to create the 
+   * cluster. <br/>
+   * 
+   * @return global configuration of the cluster.
+   */
+  public Configuration getConf() {
+    return conf;
+  }
+
+  /**
+   *
+
+  /**
+   * Return the client handle of all the Daemons.<br/>
+   * 
+   * @return map of role to daemon clients' list.
+   */
+  public Map<Enum<?>, List<AbstractDaemonClient>> getDaemons() {
+    return daemons;
+  }
+
+  /**
+   * Checks if the cluster is ready for testing. <br/>
+   * Algorithm for checking is as follows : <br/>
+   * <ul>
+   * <li> Wait for Daemon to come up </li>
+   * <li> Check if daemon is ready </li>
+   * <li> If one of the daemon is not ready, return false </li>
+   * </ul> 
+   * 
+   * @return true if whole cluster is ready.
+   * 
+   * @throws IOException
+   */
+  public boolean isReady() throws IOException {
+    for (List<AbstractDaemonClient> set : daemons.values()) {
+      for (AbstractDaemonClient daemon : set) {
+        waitForDaemon(daemon);
+        if (!daemon.isReady()) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  protected void waitForDaemon(AbstractDaemonClient d) {
+    final int TEN_SEC = 10000;
+    while(true) {
+      try {
+        LOG.info("Waiting for daemon at " + d.getHostName() + " to come up.");
+        LOG.info("Daemon might not be " +
+            "ready or the call to setReady() method hasn't been " +
+            "injected to " + d.getClass() + " ");
+        d.connect();
+        break;
+      } catch (IOException e) {
+        try {
+          Thread.sleep(TEN_SEC);
+        } catch (InterruptedException ie) {
+        }
+      }
+    }
+  }
+
+  /**
+   * Starts the cluster daemons.
+   * @throws IOException
+   */
+  public void start() throws IOException {
+    clusterManager.start();
+  }
+
+  /**
+   * Stops the cluster daemons.
+   * @throws IOException
+   */
+  public void stop() throws IOException {
+    clusterManager.stop();
+  }
+
+  /**
+   * Connect to daemon RPC ports.
+   * @throws IOException
+   */
+  public void connect() throws IOException {
+    for (List<AbstractDaemonClient> set : daemons.values()) {
+      for (AbstractDaemonClient daemon : set) {
+        daemon.connect();
+      }
+    }
+  }
+
+  /**
+   * Disconnect to daemon RPC ports.
+   * @throws IOException
+   */
+  public void disconnect() throws IOException {
+    for (List<AbstractDaemonClient> set : daemons.values()) {
+      for (AbstractDaemonClient daemon : set) {
+        daemon.disconnect();
+      }
+    }
+  }
+
+  /**
+   * Ping all the daemons of the cluster.
+   * @throws IOException
+   */
+  public void ping() throws IOException {
+    for (List<AbstractDaemonClient> set : daemons.values()) {
+      for (AbstractDaemonClient daemon : set) {
+        LOG.info("Daemon is : " + daemon.getHostName() + " pinging....");
+        daemon.ping();
+      }
+    }
+  }
+
+  /**
+   * Connect to the cluster and ensure that it is clean to run tests.
+   * @throws Exception
+   */
+  public void setUp() throws Exception {
+    while (!isReady()) {
+      Thread.sleep(1000);
+    }
+    connect();
+    ping();
+    clearAllControlActions();
+    ensureClean();
+    populateExceptionCounts();
+  }
+  
+  /**
+   * This is mainly used for the test cases to set the list of exceptions
+   * that will be excluded.
+   * @param excludeExpList list of exceptions to exclude
+   */
+  public void setExcludeExpList(String [] excludeExpList)
+  {
+    this.excludeExpList = excludeExpList;
+  }
+  
+  public void clearAllControlActions() throws IOException {
+    for (List<AbstractDaemonClient> set : daemons.values()) {
+      for (AbstractDaemonClient daemon : set) {
+        LOG.info("Daemon is : " + daemon.getHostName() + " pinging....");
+        daemon.getProxy().clearActions();
+      }
+    }
+  }
+
+  /**
+   * Ensure that the cluster is clean to run tests.
+   * @throws IOException
+   */
+  public void ensureClean() throws IOException {
+  }
+
+  /**
+   * Ensure that cluster is clean. Disconnect from the RPC ports of the daemons.
+   * @throws IOException
+   */
+  public void tearDown() throws IOException {
+    ensureClean();
+    clearAllControlActions();
+    assertNoExceptionMessages();
+    disconnect();
+  }
+
+  /**
+   * Populate the exception counts in all the daemons so that it can be checked when 
+   * the testcase has finished running.<br/>
+   * @throws IOException
+   */
+  protected void populateExceptionCounts() throws IOException {
+    for(List<AbstractDaemonClient> lst : daemons.values()) {
+      for(AbstractDaemonClient d : lst) {
+        d.populateExceptionCount(excludeExpList);
+      }
+    }
+  }
+
+  /**
+   * Assert no exception has been thrown during the sequence of the actions.
+   * <br/>
+   * @throws IOException
+   */
+  protected void assertNoExceptionMessages() throws IOException {
+    for(List<AbstractDaemonClient> lst : daemons.values()) {
+      for(AbstractDaemonClient d : lst) {
+        d.assertNoExceptionsOccurred(excludeExpList);
+      }
+    }
+  }
+}
+

Added: hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/ControlAction.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/ControlAction.java?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/ControlAction.java (added)
+++ hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/ControlAction.java Fri May 14 23:56:34 2010
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.test.system;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.hadoop.io.Writable;
+
+/**
+ * Class to represent a control action which can be performed on Daemon.<br/>
+ * 
+ */
+
+public abstract class ControlAction<T extends Writable> implements Writable {
+
+  private T target;
+
+  /**
+   * Default constructor of the Control Action, sets the Action type to zero. <br/>
+   */
+  public ControlAction() {
+  }
+
+  /**
+   * Constructor which sets the type of the Control action to a specific type. <br/>
+   * 
+   * @param target
+   *          of the control action.
+   */
+  public ControlAction(T target) {
+    this.target = target;
+  }
+
+  /**
+   * Gets the id of the control action <br/>
+   * 
+   * @return target of action
+   */
+  public T getTarget() {
+    return target;
+  }
+
+  @Override
+  public void readFields(DataInput in) throws IOException {
+    target.readFields(in);
+  }
+
+  @Override
+  public void write(DataOutput out) throws IOException {
+    target.write(out);
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof ControlAction) {
+      ControlAction<T> other = (ControlAction<T>) obj;
+      return (this.target.equals(other.getTarget()));
+    } else {
+      return false;
+    }
+  }
+  
+  
+  @Override
+  public String toString() {
+    return "Action Target : " + this.target;
+  }
+}

Added: hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/DaemonProtocol.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/DaemonProtocol.java?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/DaemonProtocol.java (added)
+++ hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/DaemonProtocol.java Fri May 14 23:56:34 2010
@@ -0,0 +1,165 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.test.system;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.io.Writable;
+import org.apache.hadoop.ipc.VersionedProtocol;
+
+/**
+ * RPC interface of a given Daemon.
+ */
+public interface DaemonProtocol extends VersionedProtocol{
+  long versionID = 1L;
+
+  /**
+   * Returns the Daemon configuration.
+   * @return Configuration
+   * @throws IOException in case of errors
+   */
+  Configuration getDaemonConf() throws IOException;
+
+  /**
+   * Check if the Daemon is alive.
+   * 
+   * @throws IOException
+   *           if Daemon is unreachable.
+   */
+  void ping() throws IOException;
+
+  /**
+   * Check if the Daemon is ready to accept RPC connections.
+   * 
+   * @return true if Daemon is ready to accept RPC connection.
+   * @throws IOException in case of errors
+   */
+  boolean isReady() throws IOException;
+
+  /**
+   * Get system level view of the Daemon process.
+   * 
+   * @return returns system level view of the Daemon process.
+   * 
+   * @throws IOException in case of errors
+   */
+  ProcessInfo getProcessInfo() throws IOException;
+  
+  /**
+   * Return a file status object that represents the path.
+   * @param path
+   *          given path
+   * @param local
+   *          whether the path is local or not
+   * @return a FileStatus object
+   * @throws FileNotFoundException when the path does not exist;
+   *         IOException see specific implementation
+   */
+  FileStatus getFileStatus(String path, boolean local) throws IOException;
+
+  /**
+   * List the statuses of the files/directories in the given path if the path is
+   * a directory.
+   * 
+   * @param path
+   *          given path
+   * @param local
+   *          whether the path is local or not
+   * @return the statuses of the files/directories in the given patch
+   * @throws IOException in case of errors
+   */
+  FileStatus[] listStatus(String path, boolean local) throws IOException;
+  
+  /**
+   * Enables a particular control action to be performed on the Daemon <br/>
+   * 
+   * @param action is a control action  to be enabled.
+   * 
+   * @throws IOException in case of errors
+   */
+  @SuppressWarnings("unchecked")
+  void sendAction(ControlAction action) throws IOException;
+  
+  /**
+   * Checks if the particular control action has be delivered to the Daemon 
+   * component <br/>
+   * 
+   * @param action to be checked.
+   * 
+   * @return true if action is still in waiting queue of 
+   *          actions to be delivered.
+   * @throws IOException in case of errors
+   */
+  @SuppressWarnings("unchecked")
+  boolean isActionPending(ControlAction action) throws IOException;
+  
+  /**
+   * Removes a particular control action from the list of the actions which the
+   * daemon maintains. <br/>
+   * <i><b>Not to be directly called by Test Case or clients.</b></i>
+   * @param action to be removed
+   * @throws IOException in case of errors
+   */
+  
+  @SuppressWarnings("unchecked")
+  void removeAction(ControlAction action) throws IOException;
+  
+  /**
+   * Clears out the list of control actions on the particular daemon.
+   * <br/>
+   * @throws IOException in case of errors
+   */
+  void clearActions() throws IOException;
+  
+  /**
+   * Gets a list of pending actions which are targeted on the specified key. 
+   * <br/>
+   * <i><b>Not to be directly used by clients</b></i>
+   * @param key target
+   * @return list of actions.
+   * @throws IOException in case of errors
+   */
+  @SuppressWarnings("unchecked")
+  ControlAction[] getActions(Writable key) throws IOException;
+
+  /**
+   * Gets the number of times a particular pattern has been found in the 
+   * daemons log file.<br/>
+   * <b><i>Please note that search spans across all previous messages of
+   * Daemon, so better practice is to get previous counts before an operation
+   * and then re-check if the sequence of action has caused any problems</i></b>
+   * @param pattern to look for in the damon's log file
+   * @param list of exceptions to ignore
+   * @return number of times the pattern if found in log file.
+   * @throws IOException in case of errors
+   */
+  int getNumberOfMatchesInLogFile(String pattern, String[] list) 
+      throws IOException;
+
+  /**
+   * Gets the user who started the particular daemon initially. <br/>
+   * 
+   * @return user who started the particular daemon.
+   * @throws IOException in case of errors
+   */
+  String getDaemonUser() throws IOException;
+}

Added: hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/ProcessInfo.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/ProcessInfo.java?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/ProcessInfo.java (added)
+++ hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/ProcessInfo.java Fri May 14 23:56:34 2010
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.test.system;
+
+import java.util.Map;
+
+import org.apache.hadoop.io.Writable;
+
+/**
+ * Daemon system level process information.
+ */
+public interface ProcessInfo extends Writable {
+  /**
+   * Get the current time in the millisecond.<br/>
+   * 
+   * @return current time on daemon clock in millisecond.
+   */
+  public long currentTimeMillis();
+
+  /**
+   * Get the environment that was used to start the Daemon process.<br/>
+   * 
+   * @return the environment variable list.
+   */
+  public Map<String,String> getEnv();
+
+  /**
+   * Get the System properties of the Daemon process.<br/>
+   * 
+   * @return the properties list.
+   */
+  public Map<String,String> getSystemProperties();
+
+  /**
+   * Get the number of active threads in Daemon VM.<br/>
+   * 
+   * @return number of active threads in Daemon VM.
+   */
+  public int activeThreadCount();
+
+  /**
+   * Get the maximum heap size that is configured for the Daemon VM. <br/>
+   * 
+   * @return maximum heap size.
+   */
+  public long maxMemory();
+
+  /**
+   * Get the free memory in Daemon VM.<br/>
+   * 
+   * @return free memory.
+   */
+  public long freeMemory();
+
+  /**
+   * Get the total used memory in Demon VM. <br/>
+   * 
+   * @return total used memory.
+   */
+  public long totalMemory();
+}
\ No newline at end of file

Added: hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/ProcessInfoImpl.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/ProcessInfoImpl.java?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/ProcessInfoImpl.java (added)
+++ hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/ProcessInfoImpl.java Fri May 14 23:56:34 2010
@@ -0,0 +1,159 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.test.system;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class ProcessInfoImpl implements ProcessInfo {
+
+  private int threadCount;
+  private long currentTime;
+  private long freemem;
+  private long maxmem;
+  private long totmem;
+  private Map<String, String> env;
+  private Map<String, String> props;
+
+  public ProcessInfoImpl() {
+    env = new HashMap<String, String>();
+    props = new HashMap<String, String>();
+  }
+
+  /**
+   * Construct a concrete process information object. <br/>
+   * 
+   * @param threadCount
+   *          count of threads.
+   * @param currentTime
+   * @param freemem
+   * @param maxmem
+   * @param totmem
+   * @param env environment list.
+   * @param props
+   */
+  public ProcessInfoImpl(int threadCount, long currentTime, long freemem,
+      long maxmem, long totmem, Map<String, String> env, 
+      Map<String, String> props) {
+    this.threadCount = threadCount;
+    this.currentTime = currentTime;
+    this.freemem = freemem;
+    this.maxmem = maxmem;
+    this.totmem = totmem;
+    this.env = env;
+    this.props = props;
+  }
+
+  @Override
+  public int activeThreadCount() {
+    return threadCount;
+  }
+
+  @Override
+  public long currentTimeMillis() {
+    return currentTime;
+  }
+
+  @Override
+  public long freeMemory() {
+    return freemem;
+  }
+
+  @Override
+  public Map<String, String> getEnv() {
+    return env;
+  }
+
+  @Override
+  public Map<String,String> getSystemProperties() {
+    return props;
+  }
+
+  @Override
+  public long maxMemory() {
+    return maxmem;
+  }
+
+  @Override
+  public long totalMemory() {
+    return totmem;
+  }
+
+  @Override
+  public void readFields(DataInput in) throws IOException {
+    this.threadCount = in.readInt();
+    this.currentTime = in.readLong();
+    this.freemem = in.readLong();
+    this.maxmem = in.readLong();
+    this.totmem = in.readLong();
+    read(in, env);
+    read(in, props);
+  }
+
+  @Override
+  public void write(DataOutput out) throws IOException {
+    out.writeInt(threadCount);
+    out.writeLong(currentTime);
+    out.writeLong(freemem);
+    out.writeLong(maxmem);
+    out.writeLong(totmem);
+    write(out, env);
+    write(out, props);
+  }
+
+  private void read(DataInput in, Map<String, String> map) throws IOException {
+    int size = in.readInt();
+    for (int i = 0; i < size; i = i + 2) {
+      String key = in.readUTF();
+      String value = in.readUTF();
+      map.put(key, value);
+    }
+  }
+
+  private void write(DataOutput out, Map<String, String> map) 
+  throws IOException {
+    int size = (map.size() * 2);
+    out.writeInt(size);
+    for (Map.Entry<String, String> entry : map.entrySet()) {
+      out.writeUTF(entry.getKey());
+      out.writeUTF(entry.getValue());
+    }
+  }
+
+  @Override
+  public String toString() {
+    StringBuffer strBuf = new StringBuffer();
+    strBuf.append(String.format("active threads : %d\n", threadCount));
+    strBuf.append(String.format("current time  : %d\n", currentTime));
+    strBuf.append(String.format("free memory  : %d\n", freemem));
+    strBuf.append(String.format("total memory  : %d\n", totmem));
+    strBuf.append(String.format("max memory  : %d\n", maxmem));
+    strBuf.append("Environment Variables : \n");
+    for (Map.Entry<String, String> entry : env.entrySet()) {
+      strBuf.append(String.format("key : %s value : %s \n", entry.getKey(),
+          entry.getValue()));
+    }
+    return strBuf.toString();
+  }
+
+}

Added: hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/ClusterProcessManager.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/ClusterProcessManager.java?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/ClusterProcessManager.java (added)
+++ hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/ClusterProcessManager.java Fri May 14 23:56:34 2010
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.test.system.process;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.hadoop.conf.Configuration;
+
+/**
+ * Interface to manage the remote processes in the cluster.
+ */
+public interface ClusterProcessManager {
+
+  /**
+   * Initialization method to pass the configuration object which is required 
+   * by the ClusterProcessManager to manage the cluster.<br/>
+   * Configuration object should typically contain all the parameters which are 
+   * required by the implementations.<br/>
+   *  
+   * @param conf configuration containing values of the specific keys which 
+   * are required by the implementation of the cluster process manger.
+   * 
+   * @throws IOException when initialization fails.
+   */
+  void init(Configuration conf) throws IOException;
+
+  /**
+   * Get the list of RemoteProcess handles of all the remote processes.
+   */
+  List<RemoteProcess> getAllProcesses();
+
+  /**
+   * Get all the roles this cluster's daemon processes have.
+   */
+  Set<Enum<?>> getRoles();
+
+  /**
+   * Method to start all the remote daemons.<br/>
+   * 
+   * @throws IOException if startup procedure fails.
+   */
+  void start() throws IOException;
+
+  /**
+   * Starts the daemon from the user specified conf dir.
+   * @param newConfLocation the dir where the new conf files reside.
+   * @throws IOException
+   */
+  void start(String newConfLocation) throws IOException;
+
+  /**
+   * Stops the daemon running from user specified conf dir.
+   * 
+   * @param newConfLocation
+   *          the dir where ther new conf files reside.
+   * @throws IOException
+   */
+  void stop(String newConfLocation) throws IOException;
+
+  /**
+   * Method to shutdown all the remote daemons.<br/>
+   * 
+   * @throws IOException if shutdown procedure fails.
+   */
+  void stop() throws IOException;
+  
+  /**
+   * Gets if multi-user support is enabled for this cluster. 
+   * <br/>
+   * @return true if multi-user support is enabled.
+   * @throws IOException
+   */
+  boolean isMultiUserSupported() throws IOException;
+
+  /**
+   * The pushConfig is used to push a new config to the daemons.
+   * @param localDir
+   * @return is the remoteDir location where config will be pushed
+   * @throws IOException
+   */
+  String pushConfig(String localDir) throws IOException;
+}

Added: hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/HadoopDaemonRemoteCluster.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/HadoopDaemonRemoteCluster.java?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/HadoopDaemonRemoteCluster.java (added)
+++ hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/HadoopDaemonRemoteCluster.java Fri May 14 23:56:34 2010
@@ -0,0 +1,404 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.test.system.process;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.util.Shell.ShellCommandExecutor;
+
+/**
+ * The concrete class which implements the start up and shut down based routines
+ * based on the hadoop-daemon.sh. <br/>
+ * 
+ * Class requires two keys to be present in the Configuration objects passed to
+ * it. Look at <code>CONF_HADOOPHOME</code> and
+ * <code>CONF_HADOOPCONFDIR</code> for the names of the
+ * configuration keys.
+ * 
+ * Following will be the format which the final command execution would look : 
+ * <br/>
+ * <code>
+ *  ssh host 'hadoop-home/bin/hadoop-daemon.sh --script scriptName 
+ *  --config HADOOP_CONF_DIR (start|stop) command'
+ * </code>
+ */
+public abstract class HadoopDaemonRemoteCluster 
+    implements ClusterProcessManager {
+
+  private static final Log LOG = LogFactory
+      .getLog(HadoopDaemonRemoteCluster.class.getName());
+
+  public static final String CONF_HADOOPNEWCONFDIR =
+    "test.system.hdrc.hadoopnewconfdir";
+  /**
+   * Key used to configure the HADOOP_HOME to be used by the
+   * HadoopDaemonRemoteCluster.
+   */
+  public final static String CONF_HADOOPHOME =
+    "test.system.hdrc.hadoophome";
+
+  public final static String CONF_SCRIPTDIR =
+    "test.system.hdrc.deployed.scripts.dir";
+  /**
+   * Key used to configure the HADOOP_CONF_DIR to be used by the
+   * HadoopDaemonRemoteCluster.
+   */
+  public final static String CONF_HADOOPCONFDIR = 
+    "test.system.hdrc.hadoopconfdir";
+
+  public final static String CONF_DEPLOYED_HADOOPCONFDIR =
+    "test.system.hdrc.deployed.hadoopconfdir";
+
+  private String hadoopHome;
+  protected String hadoopConfDir;
+  protected String scriptsDir;
+  protected String hadoopNewConfDir;
+  private final Set<Enum<?>> roles;
+  private final List<HadoopDaemonInfo> daemonInfos;
+  private List<RemoteProcess> processes;
+  protected Configuration conf;
+  
+  public static class HadoopDaemonInfo {
+    public final String cmd;
+    public final Enum<?> role;
+    public final List<String> hostNames;
+    public HadoopDaemonInfo(String cmd, Enum<?> role, List<String> hostNames) {
+      super();
+      this.cmd = cmd;
+      this.role = role;
+      this.hostNames = hostNames;
+    }
+
+    public HadoopDaemonInfo(String cmd, Enum<?> role, String hostFile) 
+        throws IOException {
+      super();
+      this.cmd = cmd;
+      this.role = role;
+      File file = new File(getDeployedHadoopConfDir(), hostFile);
+      BufferedReader reader = null;
+      hostNames = new ArrayList<String>();
+      try {
+        reader = new BufferedReader(new FileReader(file));
+        String host = null;
+        while ((host = reader.readLine()) != null) {
+          if (host.trim().isEmpty() || host.startsWith("#")) {
+            // Skip empty and possible comment lines
+            // throw new IllegalArgumentException(
+            // "Hostname could not be found in file " + hostFile);
+            continue;
+          }
+          hostNames.add(host.trim());
+        }
+        if (hostNames.size() < 1) {
+          throw new IllegalArgumentException("At least one hostname "
+              +
+            "is required to be present in file - " + hostFile);
+        }
+      } finally {
+        try {
+          reader.close();
+        } catch (IOException e) {
+          LOG.warn("Could not close reader");
+        }
+      }
+      LOG.info("Created HadoopDaemonInfo for " + cmd + " " + role + " from " 
+          + hostFile);
+    }
+  }
+
+  @Override
+  public String pushConfig(String localDir) throws IOException {
+    for (RemoteProcess process : processes){
+      process.pushConfig(localDir);
+    }
+    return hadoopNewConfDir;
+  }
+
+  public HadoopDaemonRemoteCluster(List<HadoopDaemonInfo> daemonInfos) {
+    this.daemonInfos = daemonInfos;
+    this.roles = new HashSet<Enum<?>>();
+    for (HadoopDaemonInfo info : daemonInfos) {
+      this.roles.add(info.role);
+    }
+  }
+
+  @Override
+  public void init(Configuration conf) throws IOException {
+    this.conf = conf;
+    populateDirectories(conf);
+    this.processes = new ArrayList<RemoteProcess>();
+    populateDaemons();
+  }
+
+  @Override
+  public List<RemoteProcess> getAllProcesses() {
+    return processes;
+  }
+
+  @Override
+  public Set<Enum<?>> getRoles() {
+    return roles;
+  }
+
+  /**
+   * Method to populate the hadoop home and hadoop configuration directories.
+   * 
+   * @param conf
+   *          Configuration object containing values for
+   *          CONF_HADOOPHOME and
+   *          CONF_HADOOPCONFDIR
+   * 
+   * @throws IllegalArgumentException
+   *           if the configuration or system property set does not contain
+   *           values for the required keys.
+   */
+  protected void populateDirectories(Configuration conf) {
+    hadoopHome = conf.get(CONF_HADOOPHOME);
+    hadoopConfDir = conf.get(CONF_HADOOPCONFDIR);
+    scriptsDir = conf.get(CONF_SCRIPTDIR);
+    hadoopNewConfDir = conf.get(CONF_HADOOPNEWCONFDIR);
+    if (hadoopHome == null || hadoopConfDir == null || hadoopHome.isEmpty()
+        || hadoopConfDir.isEmpty()) {
+      LOG.error("No configuration "
+          + "for the HADOOP_HOME and HADOOP_CONF_DIR passed");
+      throw new IllegalArgumentException(
+          "No Configuration passed for hadoop home " +
+          "and hadoop conf directories");
+    }
+  }
+
+  public static String getDeployedHadoopConfDir() {
+    String dir = System.getProperty(CONF_DEPLOYED_HADOOPCONFDIR);
+    if (dir == null || dir.isEmpty()) {
+      LOG.error("No configuration "
+          + "for the CONF_DEPLOYED_HADOOPCONFDIR passed");
+      throw new IllegalArgumentException(
+          "No Configuration passed for hadoop deployed conf directory");
+    }
+    return dir;
+  }
+
+  @Override
+  public void start() throws IOException {
+    for (RemoteProcess process : processes) {
+      process.start();
+    }
+  }
+
+  @Override
+  public void start(String newConfLocation)throws IOException {
+    for (RemoteProcess process : processes) {
+      process.start(newConfLocation);
+    }
+  }
+
+  @Override
+  public void stop() throws IOException {
+    for (RemoteProcess process : processes) {
+      process.kill();
+    }
+  }
+
+  @Override
+  public void stop(String newConfLocation) throws IOException {
+    for (RemoteProcess process : processes) {
+      process.kill(newConfLocation);
+    }
+  }
+
+  protected void populateDaemon(HadoopDaemonInfo info) throws IOException {
+    for (String host : info.hostNames) {
+      InetAddress addr = InetAddress.getByName(host);
+      RemoteProcess process = getProcessManager(info, 
+          addr.getCanonicalHostName());
+      processes.add(process);
+    }
+  }
+
+  protected void populateDaemons() throws IOException {
+   for (HadoopDaemonInfo info : daemonInfos) {
+     populateDaemon(info);
+   }
+  }
+
+  @Override
+  public boolean isMultiUserSupported() throws IOException {
+    return false;
+  }
+
+  protected RemoteProcess getProcessManager(
+      HadoopDaemonInfo info, String hostName) {
+    RemoteProcess process = new ScriptDaemon(info.cmd, hostName, info.role);
+    return process;
+  }
+
+  /**
+   * The core daemon class which actually implements the remote process
+   * management of actual daemon processes in the cluster.
+   * 
+   */
+  class ScriptDaemon implements RemoteProcess {
+
+    private static final String STOP_COMMAND = "stop";
+    private static final String START_COMMAND = "start";
+    private static final String SCRIPT_NAME = "hadoop-daemon.sh";
+    private static final String PUSH_CONFIG ="pushConfig.sh";
+    protected final String daemonName;
+    protected final String hostName;
+    private final Enum<?> role;
+
+    public ScriptDaemon(String daemonName, String hostName, Enum<?> role) {
+      this.daemonName = daemonName;
+      this.hostName = hostName;
+      this.role = role;
+    }
+
+    @Override
+    public String getHostName() {
+      return hostName;
+    }
+
+    private String[] getPushConfigCommand(String localDir, String remoteDir,
+        File scriptDir) throws IOException{
+      ArrayList<String> cmdArgs = new ArrayList<String>();
+      cmdArgs.add(scriptDir.getAbsolutePath() + File.separator + PUSH_CONFIG);
+      cmdArgs.add(localDir);
+      cmdArgs.add(hostName);
+      cmdArgs.add(remoteDir);
+      cmdArgs.add(hadoopConfDir);
+      return (String[]) cmdArgs.toArray(new String[cmdArgs.size()]);
+    }
+
+    private ShellCommandExecutor buildPushConfig(String local, String remote )
+        throws IOException {
+      File scriptDir = new File(scriptsDir);
+      String[] commandArgs = getPushConfigCommand(local, remote, scriptDir);
+      HashMap<String, String> env = new HashMap<String, String>();
+      ShellCommandExecutor executor = new ShellCommandExecutor(commandArgs,
+          scriptDir, env);
+      LOG.info(executor.toString());
+      return executor;
+    }
+
+    private ShellCommandExecutor createNewConfDir() throws IOException {
+      ArrayList<String> cmdArgs = new ArrayList<String>();
+      cmdArgs.add("ssh");
+      cmdArgs.add(hostName);
+      cmdArgs.add("if [ -d "+ hadoopNewConfDir+
+          " ];\n then echo Will remove existing directory;  rm -rf "+
+          hadoopNewConfDir+";\nmkdir "+ hadoopNewConfDir+"; else \n"+
+          "echo " + hadoopNewConfDir + " doesnt exist hence creating" +
+          ";  mkdir " + hadoopNewConfDir + ";\n  fi");
+      String[] cmd = (String[]) cmdArgs.toArray(new String[cmdArgs.size()]);
+      ShellCommandExecutor executor = new ShellCommandExecutor(cmd);
+      LOG.info(executor.toString());
+      return executor;
+    }
+
+    @Override
+    public void pushConfig(String localDir) throws IOException {
+      createNewConfDir().execute();
+      buildPushConfig(localDir, hadoopNewConfDir).execute();
+    }
+
+    private ShellCommandExecutor buildCommandExecutor(String command,
+        String confDir) {
+      String[] commandArgs = getCommand(command, confDir);
+      File cwd = new File(".");
+      HashMap<String, String> env = new HashMap<String, String>();
+      env.put("HADOOP_CONF_DIR", confDir);
+      ShellCommandExecutor executor
+        = new ShellCommandExecutor(commandArgs, cwd, env);
+      LOG.info(executor.toString());
+      return executor;
+    }
+
+    private File getBinDir() {
+      File binDir = new File(hadoopHome, "bin");
+      return binDir;
+    }
+
+    protected String[] getCommand(String command, String confDir) {
+      ArrayList<String> cmdArgs = new ArrayList<String>();
+      File binDir = getBinDir();
+      cmdArgs.add("ssh");
+      cmdArgs.add(hostName);
+      cmdArgs.add(binDir.getAbsolutePath() + File.separator + SCRIPT_NAME);
+      cmdArgs.add("--config");
+      cmdArgs.add(confDir);
+      // XXX Twenty internal version does not support --script option.
+      cmdArgs.add(command);
+      cmdArgs.add(daemonName);
+      return (String[]) cmdArgs.toArray(new String[cmdArgs.size()]);
+    }
+
+    @Override
+    public void kill() throws IOException {
+      kill(hadoopConfDir);
+    }
+
+    @Override
+    public void start() throws IOException {
+      start(hadoopConfDir);
+    }
+
+    public void start(String newConfLocation) throws IOException {
+      ShellCommandExecutor cme = buildCommandExecutor(START_COMMAND,
+          newConfLocation);
+      cme.execute();
+      String output = cme.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);
+        }
+      }
+    }
+
+    public void kill(String newConfLocation) throws IOException {
+      ShellCommandExecutor cme
+        = buildCommandExecutor(STOP_COMMAND, newConfLocation);
+      cme.execute();
+      String output = cme.getOutput();
+      if (!output.isEmpty()) { //getOutput() never returns null value
+        if (output.toLowerCase().contains("error")) {
+          LOG.info("Error is detected.");
+          throw new IOException("Kill error\n" + output);
+        }
+      }
+    }
+
+    @Override
+    public Enum<?> getRole() {
+      return role;
+    }
+  }
+}

Added: hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/MultiUserHadoopDaemonRemoteCluster.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/MultiUserHadoopDaemonRemoteCluster.java?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/MultiUserHadoopDaemonRemoteCluster.java (added)
+++ hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/MultiUserHadoopDaemonRemoteCluster.java Fri May 14 23:56:34 2010
@@ -0,0 +1,96 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.test.system.process;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.hadoop.test.system.process.HadoopDaemonRemoteCluster.HadoopDaemonInfo;
+
+public abstract class MultiUserHadoopDaemonRemoteCluster
+    extends HadoopDaemonRemoteCluster {
+
+  public MultiUserHadoopDaemonRemoteCluster(List<HadoopDaemonInfo> daemonInfos) {
+    super(daemonInfos);
+  }
+
+  @Override
+  protected RemoteProcess getProcessManager(
+      HadoopDaemonInfo info, String hostName) {
+    return new MultiUserScriptDaemon(info.cmd, hostName, info.role);
+  }
+
+  @Override
+  public boolean isMultiUserSupported() throws IOException {
+    return true;
+  }
+
+  class MultiUserScriptDaemon extends ScriptDaemon {
+
+    private static final String MULTI_USER_BINARY_PATH_KEY =
+        "test.system.hdrc.multi-user.binary.path";
+    private static final String MULTI_USER_MANAGING_USER =
+        "test.system.hdrc.multi-user.managinguser.";
+    private String binaryPath;
+    /**
+     * Manging user for a particular daemon is gotten by
+     * MULTI_USER_MANAGING_USER + daemonname
+     */
+    private String mangingUser;
+
+    public MultiUserScriptDaemon(
+        String daemonName, String hostName, Enum<?> role) {
+      super(daemonName, hostName, role);
+      initialize(daemonName);
+    }
+
+    private void initialize(String daemonName) {
+      binaryPath = conf.get(MULTI_USER_BINARY_PATH_KEY);
+      if (binaryPath == null || binaryPath.trim().isEmpty()) {
+        throw new IllegalArgumentException(
+            "Binary path for multi-user path is not present. Please set "
+                + MULTI_USER_BINARY_PATH_KEY + " correctly");
+      }
+      File binaryFile = new File(binaryPath);
+      if (!binaryFile.exists() || !binaryFile.canExecute()) {
+        throw new IllegalArgumentException(
+            "Binary file path is not configured correctly. Please set "
+                + MULTI_USER_BINARY_PATH_KEY
+                + " to properly configured binary file.");
+      }
+      mangingUser = conf.get(MULTI_USER_MANAGING_USER + daemonName);
+      if (mangingUser == null || mangingUser.trim().isEmpty()) {
+        throw new IllegalArgumentException(
+            "Manging user for daemon not present please set : "
+                + MULTI_USER_MANAGING_USER + daemonName + " to correct value.");
+      }
+    }
+
+    @Override
+    protected String[] getCommand(String command,String confDir) {
+      ArrayList<String> commandList = new ArrayList<String>();
+      commandList.add(binaryPath);
+      commandList.add(mangingUser);
+      commandList.add(hostName);
+      commandList.add("--config "
+          + confDir + " " + command + " " + daemonName);
+      return (String[]) commandList.toArray(new String[commandList.size()]);
+    }
+  }
+}

Added: hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/RemoteProcess.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/RemoteProcess.java?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/RemoteProcess.java (added)
+++ hadoop/common/trunk/src/test/system/java/org/apache/hadoop/test/system/process/RemoteProcess.java Fri May 14 23:56:34 2010
@@ -0,0 +1,73 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.test.system.process;
+
+import java.io.IOException;
+
+/**
+ * Interface to manage the remote process.
+ */
+public interface RemoteProcess {
+  /**
+   * Get the host on which the daemon process is running/stopped.<br/>
+   * 
+   * @return hostname on which process is running/stopped.
+   */
+  String getHostName();
+
+  /**
+   * Start a given daemon process.<br/>
+   * 
+   * @throws IOException if startup fails.
+   */
+  void start() throws IOException;
+  /**
+   * Starts a daemon from user specified conf dir. 
+   * @param newConfLocation is dir where new conf resides. 
+   * @throws IOException
+   */
+  void start(String newConfLocation) throws IOException;
+  /**
+   * Stop a given daemon process.<br/>
+   * 
+   * @throws IOException if shutdown fails.
+   */
+  void kill() throws IOException;
+  
+  /**
+   * Stops a given daemon running from user specified 
+   * conf dir. </br>
+   * @throws IOException
+   * @param newConfLocation dir location where new conf resides. 
+   */
+   void kill(String newConfLocation) throws IOException;
+  /**
+   * Get the role of the Daemon in the cluster.
+   * 
+   * @return Enum
+   */
+  Enum<?> getRole();
+  
+  /**
+   * Pushed the configuration to new configuration directory 
+   * @param localDir
+   * @throws IOException
+   */
+  void pushConfig(String localDir) throws IOException;
+}

Added: hadoop/common/trunk/src/test/system/scripts/pushConfig.sh
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/system/scripts/pushConfig.sh?rev=944521&view=auto
==============================================================================
--- hadoop/common/trunk/src/test/system/scripts/pushConfig.sh (added)
+++ hadoop/common/trunk/src/test/system/scripts/pushConfig.sh Fri May 14 23:56:34 2010
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+# local folder with new configuration file
+LOCAL_DIR=$1
+# remote daemon host
+HOST=$2
+#remote dir points to the location of new config files
+REMOTE_DIR=$3
+# remote daemon HADOOP_CONF_DIR location
+DAEMON_HADOOP_CONF_DIR=$4
+
+if [ $# -ne 4 ]; then
+  echo "Wrong number of parameters" >&2
+  exit 2
+fi
+
+ret_value=0
+
+echo The script makes a remote copy of existing ${DAEMON_HADOOP_CONF_DIR} to ${REMOTE_DIR}
+echo and populates it with new configs prepared in $LOCAL_DIR
+
+ssh ${HOST} cp -r ${DAEMON_HADOOP_CONF_DIR}/* ${REMOTE_DIR}
+ret_value=$?
+
+# make sure files are writeble
+ssh ${HOST} chmod u+w ${REMOTE_DIR}/*
+
+# copy new files over
+scp -r ${LOCAL_DIR}/* ${HOST}:${REMOTE_DIR}
+
+err_code=`echo $? + $ret_value | bc`
+echo Copying of files from local to remote returned ${err_code}
+