org.apache.hadoop.test.system.process.HadoopDaemonRemoteCluster.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.test.system.process.HadoopDaemonRemoteCluster.java

Source

/**
 * 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 {
                    if (reader != null) {
                        reader.close();
                    }
                } catch (IOException e) {
                    LOG.warn("Could not close reader", e);
                }
            }
            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;
    }

    @Override
    public RemoteProcess getDaemonProcess(String hostname, Enum<?> role) {
        RemoteProcess daemon = null;
        for (RemoteProcess p : processes) {
            if (p.getHostName().equals(hostname) && p.getRole() == role) {
                daemon = p;
                break;
            }
        }
        return daemon;
    }

    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 String pushConfig(String localDir) throws IOException {
            createNewConfDir().execute();
            buildPushConfig(localDir, hadoopNewConfDir).execute();
            return hadoopNewConfDir;
        }

        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;
        }
    }
}