/** * 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.tez.common; import java.io.File; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.hadoop.classification.InterfaceAudience.Private; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.util.Shell; import org.apache.hadoop.util.StringInterner; import org.apache.hadoop.yarn.api.ApplicationConstants; import org.apache.hadoop.yarn.api.ApplicationConstants.Environment; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.tez.dag.api.TezConfiguration; import org.apache.tez.dag.api.TezConstants; @Private public class TezYARNUtils { private static Logger LOG = LoggerFactory.getLogger(TezYARNUtils.class); public static final String ENV_NAME_REGEX = "[A-Za-z_][A-Za-z0-9_]*"; private static final Pattern VAR_SUBBER = Pattern.compile(Shell.getEnvironmentVariableRegex()); private static final Pattern VARVAL_SPLITTER = Pattern.compile( "(?<=^|,)" // preceded by ',' or line begin + '(' + ENV_NAME_REGEX + ')' // var group + '=' + "([^,]*)" // val group ); public static String getFrameworkClasspath(Configuration conf, boolean usingArchive) { StringBuilder classpathBuilder = new StringBuilder(); boolean userClassesTakesPrecedence = conf.getBoolean(TezConfiguration.TEZ_USER_CLASSPATH_FIRST, TezConfiguration.TEZ_USER_CLASSPATH_FIRST_DEFAULT); if (userClassesTakesPrecedence) { addUserSpecifiedClasspath(classpathBuilder, conf); } String [] tezLibUrisClassPath = conf.getStrings(TezConfiguration.TEZ_LIB_URIS_CLASSPATH); if(!conf.getBoolean(TezConfiguration.TEZ_IGNORE_LIB_URIS, false) && tezLibUrisClassPath != null && tezLibUrisClassPath.length != 0) { for(String c : tezLibUrisClassPath) { classpathBuilder.append(c.trim()) .append(File.pathSeparator); } } else { if(conf.getBoolean(TezConfiguration.TEZ_IGNORE_LIB_URIS, false)) { LOG.info("Ignoring '" + TezConfiguration.TEZ_LIB_URIS + "' since '" + TezConfiguration.TEZ_IGNORE_LIB_URIS + "' is set to true "); } // Legacy: Next add the tez libs, if specified via an archive. if (usingArchive) { // Add PWD/tezlib/* classpathBuilder.append(Environment.PWD.$()) .append(File.separator) .append(TezConstants.TEZ_TAR_LR_NAME) .append(File.separator) .append("*") .append(File.pathSeparator); // Legacy: Add PWD/tezlib/lib/* classpathBuilder.append(Environment.PWD.$()) .append(File.separator) .append(TezConstants.TEZ_TAR_LR_NAME) .append(File.separator) .append("lib") .append(File.separator) .append("*") .append(File.pathSeparator); } } // Last add HADOOP_CLASSPATH, if it's required. if (conf.getBoolean(TezConfiguration.TEZ_USE_CLUSTER_HADOOP_LIBS, TezConfiguration.TEZ_USE_CLUSTER_HADOOP_LIBS_DEFAULT)) { for (String c : conf.getStrings( YarnConfiguration.YARN_APPLICATION_CLASSPATH, YarnConfiguration.DEFAULT_YARN_APPLICATION_CLASSPATH)) { classpathBuilder.append(c.trim()) .append(File.pathSeparator); } } else if (conf.getBoolean(TezConfiguration.TEZ_CLASSPATH_ADD_HADOOP_CONF, TezConfiguration.TEZ_CLASSPATH_ADD_HADOOP_CONF_DEFAULT)) { // Setup HADOOP_CONF_DIR after PWD and tez-libs, if it's required. classpathBuilder.append(Environment.HADOOP_CONF_DIR.$()).append(File.pathSeparator); } if (!userClassesTakesPrecedence) { addUserSpecifiedClasspath(classpathBuilder, conf); } String classpath = classpathBuilder.toString(); return StringInterner.weakIntern(classpath); } private static void addUserSpecifiedClasspath(StringBuilder classpathBuilder, Configuration conf) { // Add any additional user-specified classpath String additionalClasspath = conf.get(TezConfiguration.TEZ_CLUSTER_ADDITIONAL_CLASSPATH_PREFIX); if (additionalClasspath != null && !additionalClasspath.trim().isEmpty()) { classpathBuilder.append(additionalClasspath) .append(File.pathSeparator); } // Add PWD:PWD/* classpathBuilder.append(Environment.PWD.$()) .append(File.pathSeparator) .append(Environment.PWD.$() + File.separator + "*") .append(File.pathSeparator); } public static void appendToEnvFromInputString(Map<String, String> env, String envString, String classPathSeparator) { if (envString != null && envString.length() > 0) { Matcher varValMatcher = VARVAL_SPLITTER.matcher(envString); while (varValMatcher.find()) { String envVar = varValMatcher.group(1); Matcher m = VAR_SUBBER.matcher(varValMatcher.group(2)); StringBuffer sb = new StringBuffer(); while (m.find()) { String var = m.group(1); // replace $env with the child's env constructed by tt's String replace = env.get(var); // if this key is not configured by the tt for the child .. get it // from the tt's env if (replace == null) replace = System.getenv(var); // If the env key is not present leave it as it is and assume it will // be set by YARN ContainerLauncher. For eg: $HADOOP_COMMON_HOME if (replace != null) m.appendReplacement(sb, Matcher.quoteReplacement(replace)); } m.appendTail(sb); addToEnvironment(env, envVar, sb.toString(), classPathSeparator); } } } public static void setEnvIfAbsentFromInputString(Map<String, String> env, String envString) { if (envString != null && envString.length() > 0) { String childEnvs[] = envString.split(","); for (String cEnv : childEnvs) { String[] parts = cEnv.split("="); // split on '=' Matcher m = VAR_SUBBER .matcher(parts[1]); StringBuffer sb = new StringBuffer(); while (m.find()) { String var = m.group(1); // replace $env with the child's env constructed by tt's String replace = env.get(var); // if this key is not configured by the tt for the child .. get it // from the tt's env if (replace == null) replace = System.getenv(var); // If the env key is not present leave it as it is and assume it will // be set by YARN ContainerLauncher. For eg: $HADOOP_COMMON_HOME if (replace != null) m.appendReplacement(sb, Matcher.quoteReplacement(replace)); } m.appendTail(sb); putIfAbsent(env, parts[0], sb.toString()); } } } public static void addToEnvironment( Map<String, String> environment, String variable, String value, String classPathSeparator) { String val = environment.get(variable); if (val == null) { val = value; } else { val = val + classPathSeparator + value; } environment.put(StringInterner.weakIntern(variable), StringInterner.weakIntern(val)); } private static void putIfAbsent(Map<String, String> env, String key, String value) { if (!env.containsKey(key)) { env.put(StringInterner.weakIntern(key), StringInterner.weakIntern(value)); } } public static void setupDefaultEnv(Map<String, String> env, Configuration conf, String userEnvKey, String userEnvDefault, String clusterDefaultEnvKey, String clusterDefaultEnvDefault, boolean usingArchive) { // Setup the CLASSPATH in environment // i.e. add { Hadoop jars, job jar, CWD } to classpath. String classpath = getFrameworkClasspath(conf, usingArchive); TezYARNUtils.addToEnvironment(env, ApplicationConstants.Environment.CLASSPATH.name(), classpath, File.pathSeparator); // Pre-pend pwd to LD_LIBRARY_PATH // Done separately here because this is known to work platform // independent TezYARNUtils.addToEnvironment(env, Environment.LD_LIBRARY_PATH.name(), Environment.PWD.$(), File.pathSeparator); TezYARNUtils.appendToEnvFromInputString(env, conf.get(userEnvKey, userEnvDefault), File.pathSeparator); // set any env from config if it is not set already TezYARNUtils.appendToEnvFromInputString(env, conf.get(clusterDefaultEnvKey, clusterDefaultEnvDefault), File.pathSeparator); } public static void replaceInEnv(Map<String, String> env, String key, String value) { env.put(StringInterner.weakIntern(key), StringInterner.weakIntern(value)); } }