blob: ad3685e18c03ca5b800d5d58875dae33721529f4 [file] [log] [blame]
/*
* 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.reef.runtime.yarn;
import net.jcip.annotations.Immutable;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.reef.runtime.common.files.RuntimeClasspathProvider;
import org.apache.reef.util.OSUtils;
import org.apache.reef.util.Optional;
import javax.inject.Inject;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Access to the classpath according to the REEF file system standard.
*/
@Immutable
public final class YarnClasspathProvider implements RuntimeClasspathProvider {
private static final Logger LOG = Logger.getLogger(YarnClasspathProvider.class.getName());
private static final Level CLASSPATH_LOG_LEVEL = Level.FINE;
private static final String YARN_TOO_OLD_MESSAGE =
"The version of YARN you are using is too old to support classpath assembly. Reverting to legacy method.";
private static final String HADOOP_CONF_DIR = OSUtils.formatVariable("HADOOP_CONF_DIR");
private static final String HADOOP_HOME = OSUtils.formatVariable("HADOOP_HOME");
private static final String HADOOP_COMMON_HOME = OSUtils.formatVariable("HADOOP_COMMON_HOME");
private static final String HADOOP_YARN_HOME = OSUtils.formatVariable("HADOOP_YARN_HOME");
private static final String HADOOP_HDFS_HOME = OSUtils.formatVariable("HADOOP_HDFS_HOME");
private static final String HADOOP_MAPRED_HOME = OSUtils.formatVariable("HADOOP_MAPRED_HOME");
// Used when we can't get a classpath from YARN
private static final String[] LEGACY_CLASSPATH_LIST = new String[]{
HADOOP_HOME + "/*",
HADOOP_HOME + "/lib/*",
HADOOP_COMMON_HOME + "/*",
HADOOP_COMMON_HOME + "/lib/*",
HADOOP_YARN_HOME + "/*",
HADOOP_YARN_HOME + "/lib/*",
HADOOP_HDFS_HOME + "/*",
HADOOP_HDFS_HOME + "/lib/*",
HADOOP_MAPRED_HOME + "/*",
HADOOP_MAPRED_HOME + "/lib/*",
HADOOP_COMMON_HOME + "/etc/hadoop/client/*",
HADOOP_HOME + "/etc/hadoop",
HADOOP_HOME + "/share/hadoop/common/*",
HADOOP_HOME + "/share/hadoop/common/lib/*",
HADOOP_HOME + "/share/hadoop/yarn/*",
HADOOP_HOME + "/share/hadoop/yarn/lib/*",
HADOOP_HOME + "/share/hadoop/hdfs/*",
HADOOP_HOME + "/share/hadoop/hdfs/lib/*",
HADOOP_HOME + "/share/hadoop/mapreduce/*",
HADOOP_HOME + "/share/hadoop/mapreduce/lib/*"
};
private final List<String> classPathPrefix;
private final List<String> classPathSuffix;
@Inject
YarnClasspathProvider(final YarnConfiguration yarnConfiguration) {
logEnvVariable();
boolean needsLegacyClasspath = false;
// will be set to true below whenever we encounter issues with the YARN Configuration
final ClassPathBuilder builder = new ClassPathBuilder();
try {
// Add the classpath actually configured on this cluster
final Optional<String[]> yarnClassPath =
getTrimmedStrings(yarnConfiguration, YarnConfiguration.YARN_APPLICATION_CLASSPATH);
final String[] yarnDefaultClassPath = YarnConfiguration.DEFAULT_YARN_CROSS_PLATFORM_APPLICATION_CLASSPATH;
if (!yarnClassPath.isPresent()) {
LOG.log(Level.SEVERE,
"YarnConfiguration.YARN_APPLICATION_CLASSPATH is empty. This indicates a broken cluster configuration.");
needsLegacyClasspath = true;
} else {
if (LOG.isLoggable(CLASSPATH_LOG_LEVEL)) {
LOG.log(CLASSPATH_LOG_LEVEL,
"YarnConfiguration.YARN_APPLICATION_CLASSPATH is [" + StringUtils.join(yarnClassPath.get(), '|') + "]");
LOG.log(CLASSPATH_LOG_LEVEL,
"YarnConfiguration.DEFAULT_YARN_CROSS_PLATFORM_APPLICATION_CLASSPATH is [" +
StringUtils.join(yarnDefaultClassPath, '|') + "]");
}
builder.addAll(yarnClassPath.get());
builder.addAll(yarnDefaultClassPath);
}
} catch (final NoSuchFieldError e) {
// This means that one of the static fields above aren't actually in YarnConfiguration.
// The reason for that is most likely that we encounter a really old version of YARN.
needsLegacyClasspath = true;
LOG.log(Level.SEVERE, YARN_TOO_OLD_MESSAGE);
}
if (needsLegacyClasspath) {
builder.addToPrefix(HADOOP_CONF_DIR);
builder.addAllToSuffix(LEGACY_CLASSPATH_LIST);
}
this.classPathPrefix = builder.getPrefixAsImmutableList();
this.classPathSuffix = builder.getSuffixAsImmutableList();
this.logClasspath();
}
/**
* Fetches the string[] under the given key, if it exists and contains entries (.length >0).
*
* @param configuration
* @param key
* @return
*/
private static Optional<String[]> getTrimmedStrings(final YarnConfiguration configuration, final String key) {
final String[] result = configuration.getTrimmedStrings(key);
if (null == result || result.length == 0) {
return Optional.empty();
} else {
return Optional.of(result);
}
}
@Override
public List<String> getDriverClasspathPrefix() {
return this.classPathPrefix;
}
@Override
public List<String> getDriverClasspathSuffix() {
return this.classPathSuffix;
}
@Override
public List<String> getEvaluatorClasspathPrefix() {
return this.classPathPrefix;
}
@Override
public List<String> getEvaluatorClasspathSuffix() {
return this.classPathSuffix;
}
private static void logEnvVariable() {
if (LOG.isLoggable(CLASSPATH_LOG_LEVEL)) {
for (final Map.Entry<String, String> entry : System.getenv().entrySet()) {
LOG.log(CLASSPATH_LOG_LEVEL, "Environment variable: Key: {0}, Value: {1}.",
new Object[]{entry.getKey(), entry.getValue()});
}
}
}
private void logClasspath() {
if (LOG.isLoggable(CLASSPATH_LOG_LEVEL)) {
final StringBuilder message = new StringBuilder("Classpath:\n\t");
message.append(StringUtils.join(classPathPrefix, "\n\t"));
message.append("\n--------------------------------\n\t");
message.append(StringUtils.join(classPathSuffix, "\n\t"));
LOG.log(CLASSPATH_LOG_LEVEL, message.toString());
}
}
}