001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *      http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019
020package org.apache.oozie.action.hadoop;
021
022import java.io.File;
023import java.util.List;
024import java.util.Map;
025
026import org.apache.hadoop.conf.Configuration;
027import org.apache.hadoop.fs.Path;
028import org.apache.hadoop.yarn.util.Apps;
029import org.apache.oozie.action.ActionExecutorException;
030import org.apache.oozie.service.ConfigurationService;
031import org.jdom.Element;
032import org.jdom.Namespace;
033
034public class ShellActionExecutor extends JavaActionExecutor {
035
036    public ShellActionExecutor() {
037        super("shell");
038    }
039
040    @Override
041    public List<Class<?>> getLauncherClasses() {
042        return null;
043    }
044
045    @Override
046    protected String getLauncherMain(Configuration launcherConf, Element actionXml) {
047        return launcherConf.get(LauncherAMUtils.CONF_OOZIE_ACTION_MAIN_CLASS, ShellMain.class.getName());
048    }
049
050    @Override
051    Configuration setupActionConf(Configuration actionConf, Context context, Element actionXml, Path appPath)
052            throws ActionExecutorException {
053        super.setupActionConf(actionConf, context, actionXml, appPath);
054        Namespace ns = actionXml.getNamespace();
055
056        String exec = actionXml.getChild("exec", ns).getTextTrim();
057        String execName = new Path(exec).getName();
058        actionConf.set(ShellMain.CONF_OOZIE_SHELL_EXEC, execName);
059
060        // Setting Shell command's arguments
061        setListInConf("argument", actionXml, actionConf, ShellMain.CONF_OOZIE_SHELL_ARGS, false);
062        // Setting Shell command's environment variable key=value
063        setListInConf("env-var", actionXml, actionConf, ShellMain.CONF_OOZIE_SHELL_ENVS, true);
064
065        // Setting capture output flag
066        actionConf.setBoolean(ShellMain.CONF_OOZIE_SHELL_CAPTURE_OUTPUT, actionXml.getChild("capture-output", ns) != null);
067
068        // Setting if ShellMain should setup HADOOP_CONF_DIR
069        boolean setupHadoopConfDir = actionConf.getBoolean(ShellMain.CONF_OOZIE_SHELL_SETUP_HADOOP_CONF_DIR,
070                ConfigurationService.getBoolean(ShellMain.CONF_OOZIE_SHELL_SETUP_HADOOP_CONF_DIR));
071        actionConf.setBoolean(ShellMain.CONF_OOZIE_SHELL_SETUP_HADOOP_CONF_DIR, setupHadoopConfDir);
072        // Setting to control if ShellMain should write log4j.properties
073        boolean writeL4J = actionConf.getBoolean(ShellMain.CONF_OOZIE_SHELL_SETUP_HADOOP_CONF_DIR_WRITE_LOG4J_PROPERTIES,
074                ConfigurationService.getBoolean(ShellMain.CONF_OOZIE_SHELL_SETUP_HADOOP_CONF_DIR_WRITE_LOG4J_PROPERTIES));
075        actionConf.setBoolean(ShellMain.CONF_OOZIE_SHELL_SETUP_HADOOP_CONF_DIR_WRITE_LOG4J_PROPERTIES, writeL4J);
076        // Setting of content of log4j.properties, if to be written
077        if (writeL4J) {
078            String l4jContent = actionConf.get(ShellMain.CONF_OOZIE_SHELL_SETUP_HADOOP_CONF_DIR_LOG4J_CONTENT,
079                    ConfigurationService.get(ShellMain.CONF_OOZIE_SHELL_SETUP_HADOOP_CONF_DIR_LOG4J_CONTENT));
080            actionConf.set(ShellMain.CONF_OOZIE_SHELL_SETUP_HADOOP_CONF_DIR_LOG4J_CONTENT, l4jContent);
081        }
082
083        return actionConf;
084    }
085
086    /**
087     * This method read a list of tag from an XML element and set the
088     * Configuration accordingly
089     *
090     * @param tag
091     * @param actionXml
092     * @param actionConf
093     * @param key
094     * @param checkKeyValue
095     * @throws ActionExecutorException
096     */
097    protected void setListInConf(String tag, Element actionXml, Configuration actionConf, String key,
098            boolean checkKeyValue) throws ActionExecutorException {
099        String[] strTagValue = null;
100        Namespace ns = actionXml.getNamespace();
101        @SuppressWarnings("unchecked")
102        List<Element> eTags = actionXml.getChildren(tag, ns);
103        if (eTags != null && eTags.size() > 0) {
104            strTagValue = new String[eTags.size()];
105            for (int i = 0; i < eTags.size(); i++) {
106                strTagValue[i] = eTags.get(i).getTextTrim();
107                if (checkKeyValue) {
108                    checkPair(strTagValue[i]);
109                }
110            }
111        }
112        ActionUtils.setStrings(actionConf, key, strTagValue);
113    }
114
115    /**
116     * Check if the key=value pair is appropriately formatted
117     * @param pair
118     * @throws ActionExecutorException
119     */
120    private void checkPair(String pair) throws ActionExecutorException {
121        String[] varValue = pair.split("=");
122        if (varValue == null || varValue.length <= 1) {
123            throw new ActionExecutorException(ActionExecutorException.ErrorType.FAILED, "JA010",
124                    "Wrong ENV format [{0}] in <env-var> , key=value format expected ", pair);
125        }
126    }
127
128    @Override
129    protected void addActionSpecificEnvVars(Map<String, String> env) {
130        Apps.setEnvFromInputString(env, "PATH=.:$PATH", File.pathSeparator);
131    }
132
133    /**
134     * Utility method to append the new value to any property.
135     *
136     * @param conf
137     * @param propertyName
138     * @param appendValue
139     */
140    private void updateProperty(Configuration conf, String propertyName, String appendValue) {
141        if (conf != null) {
142            String val = conf.get(propertyName, "");
143            if (val.length() > 0) {
144                val += ",";
145            }
146            val += appendValue;
147            conf.set(propertyName, val);
148            LOG.debug("action conf is updated with default value for property " + propertyName + ", old value :"
149                    + conf.get(propertyName, "") + ", new value :" + val);
150        }
151    }
152
153}