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, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.reef.runtime.yarn; 020 021import net.jcip.annotations.Immutable; 022import org.apache.commons.lang.StringUtils; 023import org.apache.hadoop.yarn.conf.YarnConfiguration; 024import org.apache.reef.runtime.common.files.RuntimeClasspathProvider; 025import org.apache.reef.util.OSUtils; 026 027import javax.inject.Inject; 028import java.util.List; 029import java.util.logging.Level; 030import java.util.logging.Logger; 031 032/** 033 * Access to the classpath according to the REEF file system standard. 034 */ 035@Immutable 036public final class YarnClasspathProvider implements RuntimeClasspathProvider { 037 private static final Logger LOG = Logger.getLogger(YarnClasspathProvider.class.getName()); 038 private static final Level CLASSPATH_LOG_LEVEL = Level.FINE; 039 040 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."; 041 private static final String HADOOP_CONF_DIR = OSUtils.formatVariable("HADOOP_CONF_DIR"); 042 private static final String HADOOP_HOME = OSUtils.formatVariable("HADOOP_HOME"); 043 private static final String HADOOP_COMMON_HOME = OSUtils.formatVariable("HADOOP_COMMON_HOME"); 044 private static final String HADOOP_YARN_HOME = OSUtils.formatVariable("HADOOP_YARN_HOME"); 045 private static final String HADOOP_HDFS_HOME = OSUtils.formatVariable("HADOOP_HDFS_HOME"); 046 private static final String HADOOP_MAPRED_HOME = OSUtils.formatVariable("HADOOP_MAPRED_HOME"); 047 048 // Used when we can't get a classpath from YARN 049 private static final String[] LEGACY_CLASSPATH_LIST = new String[]{ 050 HADOOP_CONF_DIR, 051 HADOOP_HOME + "/*", 052 HADOOP_HOME + "/lib/*", 053 HADOOP_COMMON_HOME + "/*", 054 HADOOP_COMMON_HOME + "/lib/*", 055 HADOOP_YARN_HOME + "/*", 056 HADOOP_YARN_HOME + "/lib/*", 057 HADOOP_HDFS_HOME + "/*", 058 HADOOP_HDFS_HOME + "/lib/*", 059 HADOOP_MAPRED_HOME + "/*", 060 HADOOP_MAPRED_HOME + "/lib/*", 061 HADOOP_HOME + "/etc/hadoop", 062 HADOOP_HOME + "/share/hadoop/common/*", 063 HADOOP_HOME + "/share/hadoop/common/lib/*", 064 HADOOP_HOME + "/share/hadoop/yarn/*", 065 HADOOP_HOME + "/share/hadoop/yarn/lib/*", 066 HADOOP_HOME + "/share/hadoop/hdfs/*", 067 HADOOP_HOME + "/share/hadoop/hdfs/lib/*", 068 HADOOP_HOME + "/share/hadoop/mapreduce/*", 069 HADOOP_HOME + "/share/hadoop/mapreduce/lib/*" 070 }; 071 private final List<String> classPathPrefix; 072 private final List<String> classPathSuffix; 073 074 @Inject 075 YarnClasspathProvider(final YarnConfiguration yarnConfiguration) { 076 boolean needsLegacyClasspath = false; // will be set to true below whenever we encounter issues with the YARN Configuration 077 final ClassPathBuilder builder = new ClassPathBuilder(); 078 079 try { 080 // Add the classpath actually configured on this cluster 081 final String[] yarnClassPath = yarnConfiguration.getTrimmedStrings(YarnConfiguration.YARN_APPLICATION_CLASSPATH); 082 if (null == yarnClassPath || yarnClassPath.length == 0) { 083 needsLegacyClasspath = true; 084 } else { 085 builder.addAll(yarnClassPath); 086 } 087 final String[] yarnDefaultClassPath = YarnConfiguration.DEFAULT_YARN_CROSS_PLATFORM_APPLICATION_CLASSPATH; 088 if (null == yarnDefaultClassPath || yarnDefaultClassPath.length == 0) { 089 LOG.log(Level.SEVERE, "YarnConfiguration.DEFAULT_YARN_CROSS_PLATFORM_APPLICATION_CLASSPATH is empty. This indicates a broken cluster configuration"); 090 needsLegacyClasspath = true; 091 } else { 092 builder.addAll(yarnDefaultClassPath); 093 } 094 } catch (final NoSuchFieldError e) { 095 // This means that one of the static fields above aren't actually in YarnConfiguration. 096 // The reason for that is most likely that we encounter a really old version of YARN. 097 needsLegacyClasspath = true; 098 LOG.log(Level.SEVERE, YARN_TOO_OLD_MESSAGE); 099 } 100 101 if (needsLegacyClasspath) { 102 builder.addAll(LEGACY_CLASSPATH_LIST); 103 } 104 105 this.classPathPrefix = builder.getPrefixAsImmutableList(); 106 this.classPathSuffix = builder.getSuffixAsImmutableList(); 107 this.logClasspath(); 108 } 109 110 @Override 111 public List<String> getDriverClasspathPrefix() { 112 return this.classPathPrefix; 113 } 114 115 @Override 116 public List<String> getDriverClasspathSuffix() { 117 return this.classPathSuffix; 118 } 119 120 @Override 121 public List<String> getEvaluatorClasspathPrefix() { 122 return this.classPathPrefix; 123 } 124 125 @Override 126 public List<String> getEvaluatorClasspathSuffix() { 127 return this.classPathSuffix; 128 } 129 130 131 private void logClasspath() { 132 if (LOG.isLoggable(CLASSPATH_LOG_LEVEL)) { 133 final StringBuilder message = new StringBuilder("Classpath:\n\t"); 134 message.append(StringUtils.join(classPathPrefix, "\n\t")); 135 message.append("\n--------------------------------\n\t"); 136 message.append(StringUtils.join(classPathSuffix, "\n\t")); 137 LOG.log(CLASSPATH_LOG_LEVEL, message.toString()); 138 } 139 } 140}