blob: 283591f449466e5a1fc1114363980f933b915a83 [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.drill.yarn.core;
import java.io.File;
import java.io.PrintStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import org.apache.drill.common.config.ConfigConstants;
import org.apache.drill.common.config.DrillConfig;
import org.apache.drill.common.scanner.ClassPathScanner;
import org.apache.drill.common.scanner.persistence.ScanResult;
import org.apache.drill.exec.ExecConstants;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigFactory;
/**
* Configuration used within the Drill-on-YARN code. Configuration comes from four
* sources (in order of precedence):
* <ol>
* <li>System properties</li>
* <li>$SITE_DIR/drill-on-yarn.conf</li>
* <li>Distribution-specific properties in $SITE_HOME/conf/doy-distrib.conf</li>
* <li>Drill-on-YARN defaults in drill-on-yarn-defaults.conf. (Which should be
* disjoint from the Drill settings.)</li>
* <li>Drill properties (via the Drill override system)</li>
* </ol>
* <p>
* Defines constants for each property, including some defined in Drill. This provides
* a uniform property access interface even if some properties migrate between DoY and
* Drill proper.
*/
public class DrillOnYarnConfig {
public static final String DEFAULTS_FILE_NAME = "drill-on-yarn-defaults.conf";
public static final String DISTRIB_FILE_NAME = "doy-distrib.conf";
public static final String CONFIG_FILE_NAME = "drill-on-yarn.conf";
public static final String DRILL_ON_YARN_PARENT = "drill.yarn";
public static final String DOY_CLIENT_PARENT = append(DRILL_ON_YARN_PARENT, "client");
public static final String DOY_AM_PARENT = append(DRILL_ON_YARN_PARENT, "am");
public static final String DOY_DRILLBIT_PARENT = append(DRILL_ON_YARN_PARENT, "drillbit");
public static final String FILES_PARENT = append(DRILL_ON_YARN_PARENT, "drill-install");
public static final String DFS_PARENT = append(DRILL_ON_YARN_PARENT, "dfs");
public static final String HTTP_PARENT = append(DRILL_ON_YARN_PARENT, "http");
public static final String YARN_PARENT = append(DRILL_ON_YARN_PARENT, "yarn");
public static final String HADOOP_PARENT = append(DRILL_ON_YARN_PARENT, "hadoop");
public static final String CLIENT_PARENT = append(DRILL_ON_YARN_PARENT, "client");
public static final String APP_NAME = append(DRILL_ON_YARN_PARENT, "app-name");
public static final String CLUSTER_ID = ExecConstants.SERVICE_NAME;
public static final String DFS_CONNECTION = append(DFS_PARENT, "connection");
public static final String DFS_APP_DIR = append(DFS_PARENT, "app-dir");
public static final String YARN_QUEUE = append(YARN_PARENT, "queue");
public static final String YARN_PRIORITY = append(YARN_PARENT, "priority");
public static final String DRILL_ARCHIVE_PATH = append(FILES_PARENT, "client-path");
public static final String DRILL_DIR_NAME = append(FILES_PARENT, "dir-name");
/**
* Key used for the Drill archive file in the AM launch config.
*/
public static final String DRILL_ARCHIVE_KEY = append(FILES_PARENT, "drill-key");
public static final String SITE_ARCHIVE_KEY = append(FILES_PARENT, "site-key");
public static final String LOCALIZE_DRILL = append(FILES_PARENT, "localize");
public static final String CONF_AS_SITE = append(FILES_PARENT, "conf-as-site");
public static final String DRILL_HOME = append(FILES_PARENT, "drill-home");
public static final String SITE_DIR = append(FILES_PARENT, "site-dir");
public static final String JAVA_LIB_PATH = append(FILES_PARENT, "library-path");
public static final String HADOOP_HOME = append(HADOOP_PARENT, "home");
public static final String HADOOP_CLASSPATH = append(HADOOP_PARENT, "class-path");
public static final String HBASE_CLASSPATH = append(HADOOP_PARENT, "hbase-class-path");
public static final String MEMORY_KEY = "memory-mb";
public static final String VCORES_KEY = "vcores";
public static final String DISKS_KEY = "disks";
public static final String VM_ARGS_KEY = "vm-args";
public static final String HEAP_KEY = "heap";
public static final String AM_MEMORY = append(DOY_AM_PARENT, MEMORY_KEY);
public static final String AM_VCORES = append(DOY_AM_PARENT, VCORES_KEY);
public static final String AM_DISKS = append(DOY_AM_PARENT, DISKS_KEY);
public static final String AM_NODE_LABEL_EXPR = append(DOY_AM_PARENT, "node-label-expr");
public static final String AM_HEAP = append(DOY_AM_PARENT, HEAP_KEY);
public static final String AM_VM_ARGS = append(DOY_AM_PARENT, VM_ARGS_KEY);
public static final String AM_POLL_PERIOD_MS = append(DOY_AM_PARENT, "poll-ms");
public static final String AM_TICK_PERIOD_MS = append(DOY_AM_PARENT, "tick-ms");
public static final String AM_PREFIX_CLASSPATH = append(DOY_AM_PARENT, "prefix-class-path");
public static final String AM_CLASSPATH = append(DOY_AM_PARENT, "class-path");
public static final String AM_DEBUG_LAUNCH = append(DOY_AM_PARENT, "debug-launch");
public static final String AM_ENABLE_AUTO_SHUTDOWN = append(DOY_AM_PARENT, "auto-shutdown");
public static final String DRILLBIT_MEMORY = append(DOY_DRILLBIT_PARENT, MEMORY_KEY);
public static final String DRILLBIT_VCORES = append(DOY_DRILLBIT_PARENT, VCORES_KEY);
public static final String DRILLBIT_DISKS = append(DOY_DRILLBIT_PARENT, DISKS_KEY);
public static final String DRILLBIT_VM_ARGS = append(DOY_DRILLBIT_PARENT, VM_ARGS_KEY);
public static final String DRILLBIT_HEAP = append(DOY_DRILLBIT_PARENT, HEAP_KEY);
public static final String DRILLBIT_DIRECT_MEM = append(DOY_DRILLBIT_PARENT, "max-direct-memory");
public static final String DRILLBIT_CODE_CACHE = append(DOY_DRILLBIT_PARENT, "code-cache");
public static final String DRILLBIT_LOG_GC = append(DOY_DRILLBIT_PARENT, "log-gc");
public static final String DRILLBIT_PREFIX_CLASSPATH = append( DOY_DRILLBIT_PARENT, "prefix-class-path");
public static final String DRILLBIT_EXTN_CLASSPATH = append( DOY_DRILLBIT_PARENT, "extn-class-path");
public static final String DRILLBIT_CLASSPATH = append(DOY_DRILLBIT_PARENT, "class-path");
public static final String DRILLBIT_MAX_RETRIES = append(DOY_DRILLBIT_PARENT, "max-retries");
public static final String DRILLBIT_DEBUG_LAUNCH = append(DOY_DRILLBIT_PARENT, "debug-launch");
public static final String DRILLBIT_HTTP_PORT = ExecConstants.HTTP_PORT;
public static final String DISABLE_YARN_LOGS = append(DOY_DRILLBIT_PARENT, "disable-yarn-logs");
public static final String DRILLBIT_USER_PORT = ExecConstants.INITIAL_USER_PORT;
public static final String DRILLBIT_BIT_PORT = ExecConstants.INITIAL_BIT_PORT;
public static final String DRILLBIT_USE_HTTPS = ExecConstants.HTTP_ENABLE_SSL;
public static final String DRILLBIT_MAX_EXTRA_NODES = append(DOY_DRILLBIT_PARENT, "max-extra-nodes");
public static final String DRILLBIT_REQUEST_TIMEOUT_SEC = append(DOY_DRILLBIT_PARENT, "request-timeout-secs");
public static final String ZK_CONNECT = ExecConstants.ZK_CONNECTION;
public static final String ZK_ROOT = ExecConstants.ZK_ROOT;
public static final String ZK_FAILURE_TIMEOUT_MS = ExecConstants.ZK_TIMEOUT;
public static final String ZK_RETRY_COUNT = ExecConstants.ZK_RETRY_TIMES;
public static final String ZK_RETRY_DELAY_MS = ExecConstants.ZK_RETRY_DELAY;
// Names selected to be parallel to Drillbit HTTP config.
public static final String HTTP_ENABLED = append(HTTP_PARENT, "enabled");
public static final String HTTP_ENABLE_SSL = append(HTTP_PARENT, "ssl-enabled");
public static final String HTTP_PORT = append(HTTP_PARENT, "port");
public static final String HTTP_AUTH_TYPE = append(HTTP_PARENT, "auth-type");
public static final String HTTP_REST_KEY = append(HTTP_PARENT, "rest-key");
public static final String HTTP_SESSION_MAX_IDLE_SECS = append(HTTP_PARENT, "session-max-idle-secs");
public static final String HTTP_DOCS_LINK = append(HTTP_PARENT, "docs-link");
public static final String HTTP_REFRESH_SECS = append(HTTP_PARENT, "refresh-secs");
public static final String HTTP_USER_NAME = append(HTTP_PARENT, "user-name");
public static final String HTTP_PASSWORD = append(HTTP_PARENT, "password");
public static final String AUTH_TYPE_NONE = "none";
public static final String AUTH_TYPE_DRILL = "drill";
public static final String AUTH_TYPE_SIMPLE = "simple";
public static final String CLIENT_POLL_SEC = append(CLIENT_PARENT, "poll-sec");
public static final String CLIENT_START_WAIT_SEC = append(CLIENT_PARENT, "start-wait-sec");
public static final String CLIENT_STOP_WAIT_SEC = append(CLIENT_PARENT, "stop-wait-sec");
public static final String CLUSTERS = append(DRILL_ON_YARN_PARENT, "cluster");
/**
* Name of the subdirectory of the container directory that will hold
* localized Drill distribution files. This name must be consistent between AM
* launch request and AM launch, and between Drillbit launch request and
* Drillbit launch. This name is fixed; there is no reason for the user to
* change it as it is visible only in the YARN container environment.
*/
public static String LOCAL_DIR_NAME = "drill";
// Environment variables used to pass information from the Drill-on-YARN
// Client to the AM, or from the AM to the Drillbit launch script.
public static final String APP_ID_ENV_VAR = "DRILL_AM_APP_ID";
public static final String DRILL_ARCHIVE_ENV_VAR = "DRILL_ARCHIVE";
public static final String SITE_ARCHIVE_ENV_VAR = "SITE_ARCHIVE";
public static final String DRILL_HOME_ENV_VAR = "DRILL_HOME";
public static final String DRILL_SITE_ENV_VAR = "DRILL_CONF_DIR";
public static final String AM_HEAP_ENV_VAR = "DRILL_AM_HEAP";
public static final String AM_JAVA_OPTS_ENV_VAR = "DRILL_AM_JAVA_OPTS";
public static final String DRILL_CLASSPATH_ENV_VAR = "DRILL_CLASSPATH";
public static final String DRILL_CLASSPATH_PREFIX_ENV_VAR = "DRILL_CLASSPATH_PREFIX";
public static final String DOY_LIBPATH_ENV_VAR = "DOY_JAVA_LIB_PATH";
public static final String DRILL_DEBUG_ENV_VAR = "DRILL_DEBUG";
/**
* Special value for the DRILL_DIR_NAME parameter to indicate to use the base
* name of the archive as the Drill home path.
*/
private static final Object BASE_NAME_MARKER = "<base>";
/**
* The name of the Drill site archive stored in dfs. Since the archive is
* created by the client as a temp file, it's local name has no meaning; we
* use this standard name on dfs.
*/
public static final String SITE_ARCHIVE_NAME = "site.tar.gz";
protected static DrillOnYarnConfig instance;
private File drillSite;
private File drillHome;
private static DrillConfig drillConfig;
private Config config;
private ScanResult classPathScan;
public static String append(String parent, String key) {
return parent + "." + key;
}
// Protected only to allow creating a test version of this class.
protected DrillOnYarnConfig( ) {
}
public static DrillOnYarnConfig load() throws DoyConfigException {
instance = new DrillOnYarnConfig();
instance.doLoad(Thread.currentThread().getContextClassLoader());
return instance;
}
/**
* Load the config.
* @param cl class loader to use for resource searches (except defaults).
* Allows test to specify a specialized version.
* <p>
* Implemented in a way that allows unit testing. The parseUrl( ) methods
* let us mock the files; the load( ) methods seem to not actually use the
* provided class loader.
*
* @throws DoyConfigException
*/
protected void doLoad(ClassLoader cl) throws DoyConfigException {
Config drillConfig = loadDrillConfig();
// Resolution order, larger numbers take precedence.
// 1. Drill-on-YARN defaults.
// File is at root of the package tree.
URL url = DrillOnYarnConfig.class.getResource(DEFAULTS_FILE_NAME);
if (url == null) {
throw new IllegalStateException(
"Drill-on-YARN defaults file is required: " + DEFAULTS_FILE_NAME);
}
config = ConfigFactory.parseURL(url).withFallback(drillConfig);
// 2. Optional distribution-specific configuration-file.
// (Lets a vendor, for example, specify the default DFS upload location
// without tinkering with the user's own settings.
url = cl.getResource(DISTRIB_FILE_NAME);
if (url != null) {
config = ConfigFactory.parseURL(url).withFallback(config);
}
// 3. User's Drill-on-YARN configuration.
// Optional since defaults are fine & ZK comes from drill-override.conf.
url = cl.getResource(CONFIG_FILE_NAME);
if (url != null) {
config = ConfigFactory.parseURL(url).withFallback(config);
}
// 4. System properties
// Allows -Dfoo=bar on the command line.
// But, note that substitutions are NOT allowed in system properties!
config = ConfigFactory.systemProperties().withFallback(config);
// Resolution allows ${foo.bar} syntax in values, but only for values
// from config files, not from system properties.
config = config.resolve();
}
private static Config loadDrillConfig() {
drillConfig = DrillConfig
.create(ConfigConstants.CONFIG_OVERRIDE_RESOURCE_PATHNAME);
return drillConfig.resolve();
}
public DrillConfig getDrillConfig() {
return drillConfig;
}
/**
* Return Drill's class path scan. This is used only in the main thread during
* initialization. Not needed by the client, so done in an unsynchronized,
* lazy fashion.
*
* @return Drill's class path scan
*/
public ScanResult getClassPathScan() {
if (classPathScan == null) {
classPathScan = ClassPathScanner.fromPrescan(drillConfig);
}
return classPathScan;
}
/**
* Obtain Drill home from the DRILL_HOME environment variable set by
* drill-config.sh, which is called from drill-on-yarn.sh. When debugging,
* DRILL_HOME must be set in the environment.
* <p>
* This information is required only by the client to prepare for uploads to
* DFS.
*
* @throws DoyConfigException
*/
public void setClientPaths() throws DoyConfigException {
setClientDrillHome();
setSiteDir();
}
private void setClientDrillHome() throws DoyConfigException {
// Try the environment variable that should have been
// set in drill-on-yarn.sh (for the client) or in the
// launch environment (for the AM.)
String homeDir = getEnv(DRILL_HOME_ENV_VAR);
// For ease in debugging, allow setting the Drill home in
// drill-on-yarn.conf.
// This setting is also used for a non-localized run.
if (DoYUtil.isBlank(homeDir)) {
homeDir = config.getString(DRILL_HOME);
}
if (DoYUtil.isBlank(homeDir)) {
throw new DoyConfigException(
"The DRILL_HOME environment variable must point to your Drill install.");
}
drillHome = new File(homeDir);
}
/**
* All environment variable access goes through this function to allow unit
* tests to replace this function to set test values. (The Java environment is
* immutable, so it is not possible for unit tests to change the actual
* environment.)
*
* @param key key to allow unit tests to replace this function
* @return environment variable
*/
protected String getEnv(String key) {
return System.getenv(key);
}
/**
* On both the client and the AM, the site directory is optional. If provided,
* it was set with the --config (or --site) option to the script that launched
* the client or AM. In both cases, the script sets the drill.yarn.siteDir
* system property (and leaks the DRILL_HOME environment variable.)
* <p>
* For ease of debugging, if neither of those are set, this method uses the
* location of the drill-on-yarn configuration file to infer the site
* directory.
* <p>
* On the client, the site directory will be the "original" directory that
* contains the user's "master" files. On the AM, the site directory is a
* localized version of the client directory. Because of the way tar works,
* both the client and AM site directories have the same name; though the path
* to that name obviously differs.
*
* @throws DoyConfigException
*/
private void setSiteDir() throws DoyConfigException {
// The site directory is the one where the config file lives.
// This should have been set in an environment variable by the launch
// script.
String sitePath = getEnv("DRILL_CONF_DIR");
if (!DoYUtil.isBlank(sitePath)) {
drillSite = new File(sitePath);
} else {
// Otherwise, let's guess it from the config file. This version assists
// in debugging as it reduces setup steps.
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = DrillOnYarnConfig.class.getClassLoader();
}
URL url = classLoader.getResource(ConfigConstants.CONFIG_OVERRIDE_RESOURCE_PATHNAME);
if (url == null) {
throw new DoyConfigException(
"Drill configuration file is missing: " + ConfigConstants.CONFIG_OVERRIDE_RESOURCE_PATHNAME);
}
File confFile;
try {
java.nio.file.Path confPath = Paths.get(url.toURI());
confFile = confPath.toFile();
} catch (URISyntaxException e) {
throw new DoyConfigException(
"Invalid path to Drill-on-YARN configuration file: "
+ url.toString(),
e);
}
drillSite = confFile.getParentFile();
}
// Verify that the site directory is not just $DRILL_HOME/conf.
// Since the calling script does not differentiate between the two cases.
// But, treat $DRILL_HOME/conf as the site directory if:
// 1. The conf-as-site property is true, or
// 2. The Drill archive resides within $DRILL_HOME.
//
// The above situations occur in certain distributions that
// ship the archive inside the site directory and don't use a
// site directory.
if (drillHome.equals(drillSite.getParentFile())
&& !config.getBoolean(CONF_AS_SITE)) {
String drillArchivePath = config
.getString(DrillOnYarnConfig.DRILL_ARCHIVE_PATH);
if (!DoYUtil.isBlank(drillArchivePath)) {
File archiveFile = new File(drillArchivePath);
if (!archiveFile.isAbsolute() && !archiveFile.getAbsolutePath()
.startsWith(drillHome.getAbsolutePath())) {
drillSite = null;
}
}
}
}
/**
* Retrieve the AM Drill home location from the DRILL_HOME variable set in the
* drill-am.sh launch script.
*
* @throws DoyConfigException
*/
public void setAmDrillHome() throws DoyConfigException {
String drillHomeStr = getEnv(DRILL_HOME_ENV_VAR);
drillHome = new File(drillHomeStr);
setSiteDir();
}
public Config getConfig() {
return instance.config;
}
public static DrillOnYarnConfig instance() {
assert instance != null;
return instance;
}
public static Config config() {
return instance().getConfig();
}
/**
* Return the Drill home on this machine as inferred from the config file
* contents or location.
*
* @return Drill home
*/
public File getLocalDrillHome() {
return drillHome;
}
public void dump() {
dump(System.out);
}
private static final String keys[] = {
// drill.yarn
APP_NAME,
CLUSTER_ID,
// drill.yarn.dfs
DFS_CONNECTION,
DFS_APP_DIR,
// drill.yarn.hadoop
HADOOP_HOME,
HADOOP_CLASSPATH,
HBASE_CLASSPATH,
// drill.yarn.yarn
YARN_QUEUE,
YARN_PRIORITY,
// drill.yarn.drill-install
DRILL_ARCHIVE_PATH,
DRILL_DIR_NAME,
LOCALIZE_DRILL,
CONF_AS_SITE,
DRILL_HOME,
DRILL_ARCHIVE_KEY,
SITE_ARCHIVE_KEY,
JAVA_LIB_PATH,
// drill.yarn.client
CLIENT_POLL_SEC,
CLIENT_START_WAIT_SEC,
CLIENT_STOP_WAIT_SEC,
// drill.yarn.am
AM_MEMORY,
AM_VCORES,
AM_DISKS,
AM_NODE_LABEL_EXPR,
AM_VM_ARGS,
AM_HEAP,
AM_POLL_PERIOD_MS,
AM_TICK_PERIOD_MS,
AM_PREFIX_CLASSPATH,
AM_CLASSPATH,
AM_DEBUG_LAUNCH,
AM_ENABLE_AUTO_SHUTDOWN,
// drill.yarn.zk
ZK_CONNECT,
ZK_ROOT,
ZK_RETRY_COUNT,
ZK_RETRY_DELAY_MS,
ZK_FAILURE_TIMEOUT_MS,
// drill.yarn.drillbit
DRILLBIT_MEMORY,
DRILLBIT_VCORES,
DRILLBIT_DISKS,
DRILLBIT_VM_ARGS,
DRILLBIT_HEAP,
DRILLBIT_DIRECT_MEM,
DRILLBIT_CODE_CACHE,
DRILLBIT_PREFIX_CLASSPATH,
DRILLBIT_EXTN_CLASSPATH,
DRILLBIT_CLASSPATH,
DRILLBIT_MAX_RETRIES,
DRILLBIT_DEBUG_LAUNCH,
DRILLBIT_MAX_EXTRA_NODES,
DRILLBIT_REQUEST_TIMEOUT_SEC,
DISABLE_YARN_LOGS,
DRILLBIT_HTTP_PORT,
DRILLBIT_USER_PORT,
DRILLBIT_BIT_PORT,
DRILLBIT_USE_HTTPS,
// drill.yarn.http
HTTP_ENABLED,
HTTP_ENABLE_SSL,
HTTP_PORT,
HTTP_AUTH_TYPE,
HTTP_SESSION_MAX_IDLE_SECS,
HTTP_DOCS_LINK,
HTTP_REFRESH_SECS,
// Do not include AM_REST_KEY: it is supposed to be secret.
// Same is true of HTTP_USER_NAME and HTTP_PASSWORD
};
private static String envVars[] = {
APP_ID_ENV_VAR,
DRILL_HOME_ENV_VAR,
DRILL_SITE_ENV_VAR,
AM_HEAP_ENV_VAR,
AM_JAVA_OPTS_ENV_VAR,
DRILL_CLASSPATH_PREFIX_ENV_VAR,
DRILL_CLASSPATH_ENV_VAR,
DRILL_ARCHIVE_ENV_VAR,
SITE_ARCHIVE_ENV_VAR,
DRILL_DEBUG_ENV_VAR
};
private void dump(PrintStream out) {
for (String key : keys) {
out.print(key);
out.print(" = ");
try {
out.println(config.getString(key));
} catch (ConfigException.Missing e) {
out.println("<missing>");
}
}
out.print(CLUSTERS);
out.println("[");
for (int i = 0; i < clusterGroupCount(); i++) {
ClusterDef.ClusterGroup cluster = ClusterDef.getCluster(config, i);
out.print(i);
out.println(" = {");
cluster.dump(" ", out);
out.println(" }");
}
out.println("]");
}
public void dumpEnv(PrintStream out) {
out.print("environment");
out.println("[");
for (String envVar : envVars) {
String value = getEnv(envVar);
out.print(envVar);
out.print(" = ");
if (value == null) {
out.print("<unset>");
} else {
out.print("\"");
out.print(value);
out.print("\"");
}
out.println();
}
out.println("]");
}
public List<NameValuePair> getPairs() {
List<NameValuePair> pairs = new ArrayList<>();
for (String key : keys) {
pairs.add(new NameValuePair(key, config.getString(key)));
}
for (int i = 0; i < clusterGroupCount(); i++) {
ClusterDef.ClusterGroup pool = ClusterDef.getCluster(config, i);
pool.getPairs(i, pairs);
}
// Add environment variables as "pseudo" properties,
// prefixed with "envt.".
for (String envVar : envVars) {
pairs.add(new NameValuePair("envt." + envVar, getEnv(envVar)));
}
return pairs;
}
public static String clusterGroupKey(int index, String key) {
return CLUSTERS + "." + index + "." + key;
}
public int clusterGroupCount() {
return config.getList(CLUSTERS).size();
}
private static String suffixes[] = { ".tar.gz", ".tgz", ".zip" };
public static String findSuffix(String baseName) {
baseName = baseName.toLowerCase();
for (String extn : suffixes) {
if (baseName.endsWith(extn)) {
return extn;
}
}
return null;
}
/**
* Get the location of Drill home on a remote machine, relative to the
* container working directory. Used when constructing a launch context.
* Assumes either the absolute path from the config file, or a constructed
* path to the localized Drill on the remote node. YARN examples use "./foo"
* to refer to container resources. But, since we cannot be sure when such a
* path is evaluated, we explicitly use YARN's PWD environment variable to get
* the absolute path.
*
* @return the remote path, with the "$PWD" environment variable.
* @throws DoyConfigException
*/
public String getRemoteDrillHome() throws DoyConfigException {
// If the application is not localized, then the user can tell us the remote
// path in the config file. Otherwise, we assume that the remote path is the
// same as the local path.
if (!config.getBoolean(LOCALIZE_DRILL)) {
String drillHomePath = config.getString(DRILL_HOME);
if (DoYUtil.isBlank(drillHomePath)) {
drillHomePath = drillHome.getAbsolutePath();
}
return drillHomePath;
}
// The application is localized. Work out the location within the container
// directory. The path starts with the "key" we specify when uploading the
// Drill archive; YARN expands the archive into a folder of that name.
String drillHome = "$PWD/" + config.getString(DRILL_ARCHIVE_KEY);
String home = config.getString(DRILL_DIR_NAME);
if (DoYUtil.isBlank(home)) {
// Assume the archive expands without a subdirectory.
}
// If the special "<base>" marker is used, assume that the path depends
// on the name of the archive, which we know from the config file.
else if (home.equals(BASE_NAME_MARKER)) {
// Otherwise, assume that the archive expands to a directory with the
// same name as the archive itself (minus the archive suffix.)
String drillArchivePath = config
.getString(DrillOnYarnConfig.DRILL_ARCHIVE_PATH);
if (DoYUtil.isBlank(drillArchivePath)) {
throw new DoyConfigException("Required config property not set: "
+ DrillOnYarnConfig.DRILL_ARCHIVE_PATH);
}
File localArchiveFile = new File(drillArchivePath);
home = localArchiveFile.getName();
String suffix = findSuffix(home);
if (suffix == null) {
throw new DoyConfigException(DrillOnYarnConfig.DRILL_ARCHIVE_PATH
+ " does not name a valid archive: " + drillArchivePath);
}
drillHome += "/" + home.substring(0, home.length() - suffix.length());
} else {
// If the user told us the name of the directory within the archive,
// use it.
drillHome += "/" + home;
}
return drillHome;
}
/**
* Get the optional remote site directory name. This name will include the
* absolute path for a non-localized application. It will return the path
* relative to the container for a localized application. In the localized
* case, the site archive is tar'ed relative to the site directory so that its
* contents are unarchived directly into the YARN-provided folder (with the
* name of the archive) key. That is, if the site directory on the client is
* /var/drill/my-site, the contents of the tar file will be
* "./drill-override.conf", etc., and the remote location is
* $PWD/site-key/drill-override.conf, where site-key is the key name used to
* localize the site archive.
*
* @return remote site directory name
*/
public String getRemoteSiteDir() {
// If the application does not use a site directory, then return null.
if (!hasSiteDir()) {
return null;
}
// If the application is not localized, then use the remote site path
// provided in the config file. Otherwise, assume that the remote path
// is the same as the local path.
if (!config.getBoolean(LOCALIZE_DRILL)) {
String drillSitePath = config.getString(SITE_DIR);
if (DoYUtil.isBlank(drillSitePath)) {
drillSitePath = drillSite.getAbsolutePath();
}
return drillSitePath;
}
// Work out the site directory name as above for the Drill directory.
// The caller must include a archive subdirectory name if required.
return "$PWD/" + config.getString(SITE_ARCHIVE_KEY);
}
/**
* Return the app ID file to use for this client run. The file is in the
* directory that holds the site dir (if a site dir is used), else the
* directory that holds Drill home (otherwise.) Not that the file does NOT go
* into the site dir or Drill home as we upload these directories (via
* archives) to DFS so we don't want to change them by adding a file.
* <p>
* It turns out that Drill allows two distinct clusters to share the same ZK
* root and/or cluster ID (just not the same combination), so the file name
* contains both parts.
*
* @return local app id file
*/
public File getLocalAppIdFile() {
String rootDir = config.getString(DrillOnYarnConfig.ZK_ROOT);
String clusterId = config.getString(DrillOnYarnConfig.CLUSTER_ID);
String key = rootDir + "-" + clusterId;
String appIdFileName = key + ".appid";
File appIdDir;
if (hasSiteDir()) {
appIdDir = drillSite.getParentFile();
} else {
appIdDir = drillHome.getParentFile();
}
return new File(appIdDir, appIdFileName);
}
public boolean hasSiteDir() {
return drillSite != null;
}
public File getLocalSiteDir() {
return drillSite;
}
/**
* Returns the DFS path to the localized Drill archive. This is an AM-only
* method as it relies on an environment variable set by the client. It is set
* only if the application is localized, it is not set for a non-localized
* run.
*
* @return the DFS path to the localized Drill archive
*/
public String getDrillArchiveDfsPath() {
return getEnv(DrillOnYarnConfig.DRILL_ARCHIVE_ENV_VAR);
}
/**
* Returns the DFS path to the localized site archive. This is an AM-only
* method as it relies on an environment variable set by the client. This
* variable is optional; if not set then the AM can infer that the application
* does not use a site archive (configuration files reside in
* $DRILL_HOME/conf), or the application is not localized.
*
* @return the DFS path to the localized site archive
*/
public String getSiteArchiveDfsPath() {
return getEnv(DrillOnYarnConfig.SITE_ARCHIVE_ENV_VAR);
}
}