From 53185c2cebb49c3c9d46a0866d1fed6abec029bf Mon Sep 17 00:00:00 2001 From: James Baiera Date: Wed, 26 Jul 2017 13:47:41 -0400 Subject: [PATCH 1/3] Removed YARN integration from master --- build.gradle | 2 +- gradle.properties | 1 - settings.gradle | 3 - yarn/README.md | 97 +---- yarn/build.gradle | 91 ----- .../hadoop/integration/yarn/YarnSuite.java | 99 ----- .../hadoop/integration/yarn/YarnTest.java | 107 ----- .../integration/yarn/YarnTestCluster.java | 113 ------ .../junit/rules/ChainedExternalResource.java | 57 --- yarn/src/itest/resources/extra.properties | 1 - yarn/src/itest/resources/yarn-test-site.xml | 15 - yarn/src/itest/resources/yarn-test.properties | 0 .../hadoop/yarn/EsYarnConstants.java | 28 -- .../hadoop/yarn/EsYarnException.java | 38 -- .../hadoop/yarn/am/AppMasterRpc.java | 106 ----- .../hadoop/yarn/am/ApplicationMaster.java | 127 ------ .../hadoop/yarn/am/EsCluster.java | 295 -------------- .../hadoop/yarn/am/EsYarnAmException.java | 40 -- .../hadoop/yarn/am/EsYarnNmException.java | 39 -- .../hadoop/yarn/am/NodeMasterRpc.java | 82 ---- .../elasticsearch/hadoop/yarn/cfg/Config.java | 209 ---------- .../hadoop/yarn/cli/YarnBootstrap.java | 247 ------------ .../hadoop/yarn/client/ClientRpc.java | 161 -------- .../hadoop/yarn/client/YarnLauncher.java | 140 ------- .../hadoop/yarn/compat/YarnCompat.java | 134 ------- .../hadoop/yarn/rpc/YarnRpc.java | 95 ----- .../hadoop/yarn/util/Assert.java | 56 --- .../hadoop/yarn/util/HttpDownloader.java | 372 ------------------ .../hadoop/yarn/util/IOUtils.java | 62 --- .../hadoop/yarn/util/PropertiesUtils.java | 116 ------ .../hadoop/yarn/util/ReflectionUtils.java | 92 ----- .../hadoop/yarn/util/StringUtils.java | 140 ------- .../hadoop/yarn/util/YarnUtils.java | 125 ------ .../hadoop/yarn/cfg/cfg.properties | 25 -- .../elasticsearch/hadoop/yarn/cli/help.txt | 10 - 35 files changed, 6 insertions(+), 3319 deletions(-) delete mode 100644 yarn/build.gradle delete mode 100644 yarn/src/itest/java/org/elasticsearch/hadoop/integration/yarn/YarnSuite.java delete mode 100644 yarn/src/itest/java/org/elasticsearch/hadoop/integration/yarn/YarnTest.java delete mode 100644 yarn/src/itest/java/org/elasticsearch/hadoop/integration/yarn/YarnTestCluster.java delete mode 100644 yarn/src/itest/java/org/junit/rules/ChainedExternalResource.java delete mode 100644 yarn/src/itest/resources/extra.properties delete mode 100644 yarn/src/itest/resources/yarn-test-site.xml delete mode 100644 yarn/src/itest/resources/yarn-test.properties delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/EsYarnConstants.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/EsYarnException.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/AppMasterRpc.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/ApplicationMaster.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/EsCluster.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/EsYarnAmException.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/EsYarnNmException.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/NodeMasterRpc.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/cfg/Config.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/cli/YarnBootstrap.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/client/ClientRpc.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/client/YarnLauncher.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/compat/YarnCompat.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/rpc/YarnRpc.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/Assert.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/HttpDownloader.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/IOUtils.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/PropertiesUtils.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/ReflectionUtils.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/StringUtils.java delete mode 100644 yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/YarnUtils.java delete mode 100644 yarn/src/main/resources/org/elasticsearch/hadoop/yarn/cfg/cfg.properties delete mode 100644 yarn/src/main/resources/org/elasticsearch/hadoop/yarn/cli/help.txt diff --git a/build.gradle b/build.gradle index 7658fc060..fa2be2ee1 100644 --- a/build.gradle +++ b/build.gradle @@ -915,7 +915,7 @@ configure(rootProject) { afterEvaluate { classDirectories = files(classDirectories.files.collect { // We're excluding Spark since the Scala bytecode trips Jacoco over and the plugin can't import yet filters - fileTree(dir: it, excludes: [ "org/elasticsearch/hadoop/yarn/**", "org/apache/hadoop/hive/**", "org/elasticsearch/spark/**", "org/elasticsearch/plugin/hadoop/**"]) + fileTree(dir: it, excludes: [ "org/apache/hadoop/hive/**", "org/elasticsearch/spark/**", "org/elasticsearch/plugin/hadoop/**"]) }) } } diff --git a/gradle.properties b/gradle.properties index 42b450b7e..3e30f594b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -39,7 +39,6 @@ hamcrestVersion = 1.3 antlrVersion = 3.4 thriftVersion = 0.5.0 esVersion = 6.0.0-alpha3-SNAPSHOT -esVersionStable = 5.5.0 groovyVersion = 2.4.4 diff --git a/settings.gradle b/settings.gradle index bee438d2b..664de8444 100644 --- a/settings.gradle +++ b/settings.gradle @@ -19,6 +19,3 @@ project(":sql-20").name = "elasticsearch-spark-20" include 'storm' project(":storm").name = "elasticsearch-storm" - -include 'yarn' -project(":yarn").name = "elasticsearch-yarn" diff --git a/yarn/README.md b/yarn/README.md index 4975d7c45..786bc99ff 100644 --- a/yarn/README.md +++ b/yarn/README.md @@ -1,95 +1,8 @@ -# Elasticsearch YARN - Beta Status +# Elasticsearch YARN -Elasticsearch YARN project allows Elasticsearch to run within a Hadoop YARN cluster, handling the provisioning and life-cycle of the Elasticsearch cluster the command-line interface (CLI). -Note the project is in Beta status. +## :warning: Elasticsearch YARN has been removed -## Requirements - -Elasticsearch YARN requires Hadoop 2.4.x or higher (the latest stable release is recommended). - -## Install - -Simply download elasticsearch-yarn-.jar in a location of choice and make sure to have Hadoop available in your classpath; double check through the `hadoop version` command: - - - > ls - elasticsearch-yarn-6.0.0-alpha-2 - - > hadoop version - Hadoop 2.4.1 - Subversion http://svn.apache.org/repos/asf/hadoop/common -r 1604318 - Compiled by jenkins on 2014-06-21T05:43Z - Compiled with protoc 2.5.0 - From source with checksum bb7ac0a3c73dc131f4844b873c74b630 - This command was run using /opt/share/hadoop/common/hadoop-common-2.4.1.jar - - -## Usage - -Simply run `hadoop jar elasticsearch-yarn-.jar` to get a list of available actions: - - > hadoop jar elasticsearch-yarn-.jar - No command specified - Usage: - -download-es : Downloads Elasticsearch.zip - -install : Installs/Provisions Elasticsearch-YARN into HDFS - -install-es : Installs/Provisions Elasticsearch into HDFS - -start : Starts provisioned Elasticsearch in YARN - -status : Reports status of Elasticsearch in YARN - -stop : Stops Elasticsearch in YARN - -help : Prints this help - - Configuration options can be specified _after_ each command; see the documentation for more information. - - -Each command should be self-explanatory. The typical usage scenario is: - -### Download Elasticsearch version needed - -This is a _one-time_ action; if you already have Elasticsearch at hand, deploy it under `downloads` folder. To wit: - - > hadoop jar elasticsearch-yarn- -download-es - Downloading Elasticsearch 6.0.0-alpha-2 - Downloading ......................................................................................DONE - -### Provision Elasticsearch into HDFS - -Now that we have downloaded Elasticsearch, let us upload it into HDFS so it becomes available to the Hadoop nodes. -This is another _one-time_ action (as long as your HDFS cluster and the target location remain in place): - - > hadoop jar elasticsearch-yarn-.jar -install-es - Uploaded /opt/es-yarn/downloads/elasticsearch-.zip to HDFS at hdfs://127.0.0.1:50463/apps/elasticsearch/elasticsearch-.zip - -This command uploads the `elasticsearch-.zip` (that we just downloaded) to HDFS (based on the Hadoop configuration detected in the classpath) under `/apps/elasticsearch` folder. - -### Provision Elasticsearch-YARN into HDFS - -Let us do the same _one-time_ command with the Elasticsearch-YARN jar: - - > hadoop jar elasticsearch-yarn-.jar -install - Uploaded opt/es-yarn/elasticsearch-yarn-.jar to HDFS at hdfs://127.0.0.1:50463/apps/elasticsearch/elasticsearch-yarn-.jar - -### Start Elasticsearch on YARN - -Now that we have the necessary artifacts in HDFS, let us start Elasticsearch: - - > hadoop jar elasticsearch-yarn-.jar -start - Launched Elasticsearch-YARN cluster [application_1415813090693_0001@http://hadoop:8088/proxy/application_1415813090693_0001/] at Wed Nov 12 19:24:53 EET 2014 - -That's it! - -### List Elasticsearch clusters in YARN - -There are plenty of tools in Hadoop to check running YARN applications; with Elasticsearch YARN try the `-status` command: - - > hadoop jar elasticsearch-yarn-.jar -status - Id State Status Start Time Finish Time Tracking URL - application_1415813090693_0001 RUNNING UNDEFINED 11/12/14 7:24 PM N/A http://hadoop:8088/proxy/application_1415813090693_0001/A - -### Stop Elasticsearch clusters in YARN - -Simply use the `-stop` command: - - > hadoop jar elasticsearch-yarn-.jar -stop - Stopped Elasticsearch Cluster with id application_1415813090693_0001 +The Elasticsearch YARN beta has been removed as of ES-Hadoop 6.0.0. For more information about the removal, please see +the [deprecation notice on Github](https://github.com/elastic/elasticsearch-hadoop/issues/1000), or join the [discussion +topic](https://discuss.elastic.co/t/deprecation-notice-old-mr-apis-and-es-yarn/92860/3) on our forums. diff --git a/yarn/build.gradle b/yarn/build.gradle deleted file mode 100644 index 4262f10f8..000000000 --- a/yarn/build.gradle +++ /dev/null @@ -1,91 +0,0 @@ -description = 'Elasticsearch YARN' - -configurations { - hadoop2 -} - -dependencies { - provided("org.elasticsearch:elasticsearch:$esVersion") - provided("org.apache.hadoop:hadoop-client:$hadoop2Version") - - testCompile("org.apache.hadoop:hadoop-common:$hadoop2Version") - testCompile("org.apache.hadoop:hadoop-common:$hadoop2Version:tests") - testCompile("org.apache.hadoop:hadoop-yarn-server-tests:$hadoop2Version") - testCompile("org.apache.hadoop:hadoop-yarn-server-tests:$hadoop2Version:tests") - testCompile("org.apache.hadoop:hadoop-hdfs:$hadoop2Version") - testCompile("org.apache.hadoop:hadoop-hdfs:$hadoop2Version:tests") -} - -processResources { - expand (version: project.version, esVersionStable: project.esVersionStable) -} - -jar { - manifest { - from manifestTemplate - attributes['Implementation-Title'] = 'elasticsearch-yarn' - attributes['Main-Class'] = 'org.elasticsearch.hadoop.yarn.cli.YarnBootstrap' - } - - from("$rootDir/docs/src/info") { - include "license.txt" - include "notice.txt" - into "META-INF" - expand(copyright: new Date().format('yyyy'), version: project.version) - } -} - -def baseZip(Zip zip) { - zip.group = "Distribution" - - artifacts { s3 zip } - - zip.from("../") { - include "LICENSE.txt" - include "NOTICE.txt" - //expand(yyyy: new Date().format("yyyy"), version: project.version) - } - zip.from (".") { include "README.md" } - zip.from jar.archivePath - - // tell Gradle about our output (for incremental build) - disabled for now since the sha1 is created alongside the zip - // zip.outputs.file file(zip.archivePath.absolutePath + '.sha1.txt') - - // execute phase - zip.doLast { - ant.checksum(file: zip.archivePath, algorithm: 'SHA1', format: 'MD5SUM', fileext: '.sha1.txt') - } -} - -task distZipHadoop2(type: Zip, dependsOn: [jar]) { zipTask -> - baseZip(zipTask) - description = "Builds archive (with Hadoop2/YARN dependencies) suitable for download page." - - from configurations.hadoop2.allArtifacts.files - from configurations.hadoop2 -} - -task distZipNoHadoop(type: Zip, dependsOn: [jar]) { zipTask -> - baseZip(zipTask) - description = "Builds archive (without any Hadoop dependencies) suitable for download page." - classifier = "light" -} - -task distZip(dependsOn : [distZipHadoop2, distZipNoHadoop]) { - group = "Distribution" - description = "Builds all distribution zips for Elasticseach YARN" -} - -pack() { - artifacts { - archives distZipHadoop2 - archives distZipNoHadoop - } -} - -uploadToS3() { - ext.toDir = "elasticsearch/elasticsearch-yarn" -} - -assemble.dependsOn = ['jar'] -defaultTasks 'build' \ No newline at end of file diff --git a/yarn/src/itest/java/org/elasticsearch/hadoop/integration/yarn/YarnSuite.java b/yarn/src/itest/java/org/elasticsearch/hadoop/integration/yarn/YarnSuite.java deleted file mode 100644 index 4d0b32804..000000000 --- a/yarn/src/itest/java/org/elasticsearch/hadoop/integration/yarn/YarnSuite.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.integration.yarn; - -import java.io.File; -import java.io.FilenameFilter; -import java.io.StringWriter; -import java.util.Arrays; -import java.util.Properties; - -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.hdfs.DistributedFileSystem; -import org.apache.hadoop.yarn.conf.YarnConfiguration; -import org.elasticsearch.hadoop.yarn.client.ClientRpc; -import org.elasticsearch.hadoop.yarn.util.Assert; -import org.elasticsearch.hadoop.yarn.util.PropertiesUtils; -import org.junit.ClassRule; -import org.junit.Ignore; -import org.junit.rules.ChainedExternalResource; -import org.junit.rules.ExternalResource; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -@RunWith(Suite.class) -@Suite.SuiteClasses({ YarnTest.class }) -@Ignore("Classpath madness") -public class YarnSuite { - - public static ClientRpc YC; - public static Properties TEST_PROPS = PropertiesUtils.load(YarnSuite.class, "/yarn-test.properties"); - public static YarnConfiguration CFG = new YarnConfiguration(); - - static { - CFG.setInt(YarnConfiguration.DEBUG_NM_DELETE_DELAY_SEC, -1); - } - - public static YarnTestCluster CLUSTER = new YarnTestCluster(CFG); - public static DistributedFileSystem FS; - public static File CLIENT_JAR; - - public static ExternalResource YARN_CLIENT = new ExternalResource() { - - @Override - protected void before() throws Throwable { - YC = new ClientRpc(CFG); - YC.start(); - } - - @Override - protected void after() { - YC.close(); - } - }; - - public static ExternalResource PROVISION_JARS = new ExternalResource() { - @Override - protected void before() throws Throwable { - // initialize FS (now that the cluster has started) - FS = CLUSTER.fs(); - - File libs = new File("build/libs"); - File[] clientLibs = libs.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.contains("-yarn"); - } - }); - - Assert.isTrue(clientLibs.length == 1, "Check there is exactly one (client) jar " + Arrays.toString(clientLibs)); - CLIENT_JAR = clientLibs[0]; - - //TEST_PROPS.setProperty("hdfs.esyarn.jar", CLIENT_JAR.getAbsolutePath()); - - StringWriter sw = new StringWriter(); - Configuration.dumpConfiguration(CFG, sw); - System.out.println("Configuration before starting the test " + sw); - } - }; - - @ClassRule - public static ExternalResource RES = new ChainedExternalResource(CLUSTER, PROVISION_JARS, YARN_CLIENT); - -} \ No newline at end of file diff --git a/yarn/src/itest/java/org/elasticsearch/hadoop/integration/yarn/YarnTest.java b/yarn/src/itest/java/org/elasticsearch/hadoop/integration/yarn/YarnTest.java deleted file mode 100644 index 5cc4867ca..000000000 --- a/yarn/src/itest/java/org/elasticsearch/hadoop/integration/yarn/YarnTest.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.integration.yarn; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import org.apache.hadoop.yarn.api.records.ApplicationId; -import org.apache.hadoop.yarn.api.records.ApplicationReport; -import org.elasticsearch.hadoop.yarn.cli.YarnBootstrap; -import org.junit.Before; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.Ignore; -import org.junit.runners.MethodSorters; - -import static org.elasticsearch.hadoop.integration.yarn.YarnSuite.CFG; -import static org.elasticsearch.hadoop.integration.yarn.YarnSuite.CLIENT_JAR; -import static org.elasticsearch.hadoop.integration.yarn.YarnSuite.YC; - -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Ignore("Classpath madness") -public class YarnTest { - - private YarnBootstrap bootstrap; - private final List testEnv = new ArrayList(); - - @Before - public void before() { - bootstrap = new YarnBootstrap(); - bootstrap.setConf(CFG); - - testEnv.add("hdfs.es.yarn.jar=" + CLIENT_JAR.getName()); - testEnv.add("internal.es.yarn.file=" + CLIENT_JAR.getAbsolutePath()); - testEnv.add("download.local.dir=./build/downloads"); - // for tests we don't need gigs - testEnv.add("container.mem=512"); - testEnv.add("sys.prop.es.security.manager.enabled=false"); - } - - @Test - public void testStartup() throws Exception { - System.out.println(YC.listApps()); - } - - @Test - public void test1InstallEsYarn() throws Exception { - bootstrap.run(cmdArgs("-install")); - } - - @Test - public void test2Download() throws Exception { - bootstrap.run(cmdArgs("-download-es")); - } - - @Test - public void test3Install() throws Exception { - bootstrap.run(cmdArgs("-install-es")); - } - - @Test - public void test4Start() throws Exception { - bootstrap.run(cmdArgs("-start", "loadConfig=" + getClass().getResource("/extra.properties").toURI().toString())); - final List apps = YC.listEsClusters(); - System.out.println(apps); - final ApplicationId appId = apps.get(0).getApplicationId(); - YC.waitForApp(appId, TimeUnit.SECONDS.toMillis(50)); - //System.in.read(); - } - - @Test - public void test5List() throws Exception { - bootstrap.run(cmdArgs("-status")); - //System.in.read(); - } - - @Test - public void test6Stop() throws Exception { - //System.in.read(); - bootstrap.run(cmdArgs("-stop")); - } - - private String[] cmdArgs(String... args) { - List argsList = new ArrayList(); - argsList.addAll(Arrays.asList(args)); - argsList.addAll(testEnv); - return argsList.toArray(new String[argsList.size()]); - } -} \ No newline at end of file diff --git a/yarn/src/itest/java/org/elasticsearch/hadoop/integration/yarn/YarnTestCluster.java b/yarn/src/itest/java/org/elasticsearch/hadoop/integration/yarn/YarnTestCluster.java deleted file mode 100644 index dcc0e55c1..000000000 --- a/yarn/src/itest/java/org/elasticsearch/hadoop/integration/yarn/YarnTestCluster.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.integration.yarn; - -import java.io.IOException; - -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.hdfs.DistributedFileSystem; -import org.apache.hadoop.hdfs.MiniDFSCluster; -import org.apache.hadoop.yarn.conf.YarnConfiguration; -import org.apache.hadoop.yarn.server.MiniYARNCluster; -import org.junit.rules.ExternalResource; - -public class YarnTestCluster extends ExternalResource { - - private MiniYARNCluster yarnCluster = null; - private MiniDFSCluster dfsCluster = null; - - private int nodes = 1; - private final String CLUSTER_NAME = "es-yarn-cluster"; - - private String tempDir; - - private final YarnConfiguration cfg; - - YarnTestCluster(YarnConfiguration cfg) { - this(cfg, 1); - } - - YarnTestCluster(YarnConfiguration cfg, int nodes) { - this.cfg = cfg; - this.nodes = nodes; - } - - MiniYARNCluster yarnCluster() { - return yarnCluster; - } - - DistributedFileSystem fs() { - try { - return dfsCluster.getFileSystem(); - } catch (IOException ex) { - throw new IllegalStateException(ex); - } - } - - @Override - protected void before() throws Throwable { - if (yarnCluster != null) { - return; - } - - System.out.println("Starting YARN cluster..."); - - //tempDir = System.getProperty("java.io.tmpdir"); - //System.setProperty("java.io.tmpdir", "/tmp-yarn"); - - // FileContext.DEFAULT_PERM.fromShort((short) 777); - // FileContext.DIR_DEFAULT_PERM.fromShort((short) 777); - // FileContext.FILE_DEFAULT_PERM.fromShort((short) 777); - //ContainerExecutor.TASK_LAUNCH_SCRIPT_PERMISSION.fromShort((short) 777); - - // make sure to use IP discovery - Configuration.addDefaultResource("yarn-test-site.xml"); - - // disable am deletion - cfg.set(YarnConfiguration.DEBUG_NM_DELETE_DELAY_SEC, "-1"); - cfg.set(MiniDFSCluster.HDFS_MINIDFS_BASEDIR, "build/es-yarn/" + CLUSTER_NAME + "-dfs"); - - dfsCluster = new MiniDFSCluster.Builder(cfg).numDataNodes(nodes).build(); - System.out.println("Started DFS cluster..."); - - cfg.set(YarnConfiguration.YARN_MINICLUSTER_FIXED_PORTS, "true"); - yarnCluster = new MiniYARNCluster(CLUSTER_NAME, nodes, 1, 1); - yarnCluster.init(cfg); - yarnCluster.start(); - System.out.println("Started YARN cluster..."); - } - - @Override - protected void after() { - //System.setProperty("java.io.tmpdir", tempDir); - - if (yarnCluster != null) { - System.out.println("Stopping YARN cluster..."); - // same as close but without the IOException - yarnCluster.stop(); - yarnCluster = null; - } - - if (dfsCluster != null) { - System.out.println("Stopping DFS cluster..."); - dfsCluster.shutdown(); - dfsCluster = null; - } - } -} \ No newline at end of file diff --git a/yarn/src/itest/java/org/junit/rules/ChainedExternalResource.java b/yarn/src/itest/java/org/junit/rules/ChainedExternalResource.java deleted file mode 100644 index 361f9c461..000000000 --- a/yarn/src/itest/java/org/junit/rules/ChainedExternalResource.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.junit.rules; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -public class ChainedExternalResource extends ExternalResource { - - private ExternalResource[] resources; - - private static final Log log = LogFactory.getLog(ChainedExternalResource.class); - - public ChainedExternalResource(ExternalResource... resources) { - this.resources = resources; - } - - @Override - protected void before() throws Throwable { - for (ExternalResource resource : resources) { - try { - resource.before(); - } catch (Exception ex) { - log.warn("Cannot 'before' for resource " + resource, ex); - } - } - } - - @Override - protected void after() { - // call after in reverse order - for (int i = resources.length - 1; i >= 0; i--) { - ExternalResource resource = resources[i]; - try { - resource.after(); - } catch (Exception ex) { - log.warn("Cannot 'after' for resource " + resource, ex); - } - } - } -} diff --git a/yarn/src/itest/resources/extra.properties b/yarn/src/itest/resources/extra.properties deleted file mode 100644 index b3e478784..000000000 --- a/yarn/src/itest/resources/extra.properties +++ /dev/null @@ -1 +0,0 @@ -env.FOO=BAR \ No newline at end of file diff --git a/yarn/src/itest/resources/yarn-test-site.xml b/yarn/src/itest/resources/yarn-test-site.xml deleted file mode 100644 index a84e9d8fe..000000000 --- a/yarn/src/itest/resources/yarn-test-site.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - hadoop.security.token.service.use_ip - true - - - - yarn.scheduler.minimum-allocation-mb - 32 - - - diff --git a/yarn/src/itest/resources/yarn-test.properties b/yarn/src/itest/resources/yarn-test.properties deleted file mode 100644 index e69de29bb..000000000 diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/EsYarnConstants.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/EsYarnConstants.java deleted file mode 100644 index 5dd80f21c..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/EsYarnConstants.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn; - -// NB: don't use . since it won't work on *nix -// to be consistent use only UPPER CASE vars -public interface EsYarnConstants { - - String FS_URI = "ES_YARN_FS_URI"; - - String CFG_PROPS = "ES_YARN_CFG_PROPERTIES"; -} diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/EsYarnException.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/EsYarnException.java deleted file mode 100644 index cf6d63b2c..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/EsYarnException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn; - -public class EsYarnException extends RuntimeException { - - public EsYarnException() { - super(); - } - - public EsYarnException(String message, Throwable cause) { - super(message, cause); - } - - public EsYarnException(String message) { - super(message); - } - - public EsYarnException(Throwable cause) { - super(cause); - } -} diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/AppMasterRpc.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/AppMasterRpc.java deleted file mode 100644 index 7bb8792eb..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/AppMasterRpc.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.am; - -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.yarn.api.protocolrecords.AllocateResponse; -import org.apache.hadoop.yarn.api.protocolrecords.RegisterApplicationMasterResponse; -import org.apache.hadoop.yarn.api.records.FinalApplicationStatus; -import org.apache.hadoop.yarn.client.api.AMRMClient; -import org.apache.hadoop.yarn.client.api.AMRMClient.ContainerRequest; -import org.apache.hadoop.yarn.client.api.NMTokenCache; -import org.apache.hadoop.yarn.conf.YarnConfiguration; -import org.elasticsearch.hadoop.yarn.compat.YarnCompat; - -class AppMasterRpc implements AutoCloseable { - - private final YarnConfiguration cfg; - private AMRMClient client; - private final NMTokenCache nmTokenCache; - - public AppMasterRpc(Configuration cfg, NMTokenCache nmTokenCache) { - this.cfg = new YarnConfiguration(cfg); - this.nmTokenCache = nmTokenCache; - } - - public void start() { - if (client != null) { - return; - } - - client = AMRMClient.createAMRMClient(); - YarnCompat.setNMTokenCache(client, nmTokenCache); - client.init(cfg); - client.start(); - } - - public RegisterApplicationMasterResponse registerAM() { - try { - return client.registerApplicationMaster("", 0, ""); - } catch (Exception ex) { - throw new EsYarnAmException(ex); - } - } - - public void failAM() { - unregisterAM(FinalApplicationStatus.FAILED); - } - - public void finishAM() { - unregisterAM(FinalApplicationStatus.SUCCEEDED); - } - - private void unregisterAM(FinalApplicationStatus status) { - try { - client.unregisterApplicationMaster(status, "", ""); - } catch (Exception ex) { - throw new EsYarnAmException(ex); - } - } - - public void addContainerRequest(ContainerRequest req) { - client.addContainerRequest(req); - } - - public AllocateResponse allocate(int step) { - try { - return client.allocate(step); - } catch (Exception ex) { - throw new EsYarnAmException(ex); - } - } - - public Configuration getConfiguration() { - return cfg; - } - - public NMTokenCache getNMToCache() { - return nmTokenCache; - } - - @Override - public void close() { - if (client == null) { - return; - } - - client.stop(); - client = null; - } -} diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/ApplicationMaster.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/ApplicationMaster.java deleted file mode 100644 index 029935a83..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/ApplicationMaster.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.am; - -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.fs.FileSystem; -import org.apache.hadoop.yarn.api.protocolrecords.RegisterApplicationMasterResponse; -import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; -import org.apache.hadoop.yarn.api.records.NMToken; -import org.apache.hadoop.yarn.client.api.NMTokenCache; -import org.apache.hadoop.yarn.conf.YarnConfiguration; -import org.elasticsearch.hadoop.yarn.cfg.Config; -import org.elasticsearch.hadoop.yarn.util.Assert; -import org.elasticsearch.hadoop.yarn.util.PropertiesUtils; -import org.elasticsearch.hadoop.yarn.util.YarnUtils; - -import static org.elasticsearch.hadoop.yarn.EsYarnConstants.CFG_PROPS; -import static org.elasticsearch.hadoop.yarn.EsYarnConstants.FS_URI; - -public class ApplicationMaster implements AutoCloseable { - - private static final Log log = LogFactory.getLog(ApplicationMaster.class); - - private ApplicationAttemptId appId; - private final Map env; - private AppMasterRpc rpc; - private final Configuration cfg; - private EsCluster cluster; - private NMTokenCache nmTokenCache; - private final Config appConfig; - - private RegisterApplicationMasterResponse amResponse; - - - ApplicationMaster(Map env) { - this.env = env; - cfg = new YarnConfiguration(); - if (env.containsKey(FS_URI)) { - cfg.set(FileSystem.FS_DEFAULT_NAME_KEY, env.get(FS_URI)); - } - appConfig = new Config(PropertiesUtils.propsFromBase64String(env.get(CFG_PROPS))); - } - - void run() { - log.info("Starting ApplicationMaster..."); - - if (nmTokenCache == null) { - nmTokenCache = new NMTokenCache(); - } - - if (rpc == null) { - rpc = new AppMasterRpc(cfg, nmTokenCache); - rpc.start(); - } - - // register AM - appId = YarnUtils.getApplicationAttemptId(env); - Assert.notNull(appId, "ApplicationAttemptId cannot be found in env %s" + env); - amResponse = rpc.registerAM(); - updateTokens(); - cluster = new EsCluster(rpc, appConfig, env); - try { - cluster.start(); - } finally { - close(); - } - } - - - private void updateTokens() { - for (NMToken nmToken : amResponse.getNMTokensFromPreviousAttempts()) { - nmTokenCache.setToken(nmToken.getNodeId().toString(), nmToken.getToken()); - } - } - - @Override - public void close() { - boolean hasFailed = (cluster == null || cluster.hasFailed()); - - try { - if (cluster != null) { - cluster.close(); - cluster = null; - } - - } finally { - if (amResponse != null) { - updateTokens(); - } - if (hasFailed) { - rpc.failAM(); - } - else { - rpc.finishAM(); - } - } - } - - public static void main(String[] args) { - ApplicationMaster am = new ApplicationMaster(System.getenv()); - try { - am.run(); - } finally { - am.close(); - } - } -} \ No newline at end of file diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/EsCluster.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/EsCluster.java deleted file mode 100644 index bbc1af725..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/EsCluster.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.am; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.fs.FileStatus; -import org.apache.hadoop.fs.FileSystem; -import org.apache.hadoop.fs.Path; -import org.apache.hadoop.security.SecurityUtil; -import org.apache.hadoop.security.UserGroupInformation; -import org.apache.hadoop.yarn.api.ApplicationConstants; -import org.apache.hadoop.yarn.api.protocolrecords.AllocateResponse; -import org.apache.hadoop.yarn.api.records.Container; -import org.apache.hadoop.yarn.api.records.ContainerExitStatus; -import org.apache.hadoop.yarn.api.records.ContainerId; -import org.apache.hadoop.yarn.api.records.ContainerLaunchContext; -import org.apache.hadoop.yarn.api.records.ContainerStatus; -import org.apache.hadoop.yarn.api.records.LocalResource; -import org.apache.hadoop.yarn.api.records.LocalResourceType; -import org.apache.hadoop.yarn.api.records.LocalResourceVisibility; -import org.apache.hadoop.yarn.api.records.Priority; -import org.apache.hadoop.yarn.api.records.Resource; -import org.apache.hadoop.yarn.client.api.AMRMClient.ContainerRequest; -import org.apache.hadoop.yarn.util.ConverterUtils; -import org.apache.hadoop.yarn.util.Records; -import org.elasticsearch.hadoop.yarn.cfg.Config; -import org.elasticsearch.hadoop.yarn.compat.YarnCompat; -import org.elasticsearch.hadoop.yarn.util.StringUtils; -import org.elasticsearch.hadoop.yarn.util.YarnUtils; - -/** - * logical cluster managing the global lifecycle for its multiple containers. - */ -class EsCluster implements AutoCloseable { - - private static final Log log = LogFactory.getLog(EsCluster.class); - - private final AppMasterRpc amRpc; - private final NodeMasterRpc nmRpc; - private final Configuration cfg; - private final Config appConfig; - private final Map masterEnv; - - private volatile boolean running = false; - private volatile boolean clusterHasFailed = false; - - private final Set allocatedContainers = new LinkedHashSet(); - private final Set completedContainers = new LinkedHashSet(); - - public EsCluster(final AppMasterRpc rpc, Config appConfig, Map masterEnv) { - this.amRpc = rpc; - this.cfg = rpc.getConfiguration(); - this.nmRpc = new NodeMasterRpc(cfg, rpc.getNMToCache()); - this.appConfig = appConfig; - this.masterEnv = masterEnv; - } - - public void start() { - running = true; - nmRpc.start(); - - UserGroupInformation.setConfiguration(cfg); - attemptKeytabLogin(); - - log.info(String.format("Allocating Elasticsearch cluster with %d nodes", appConfig.containersToAllocate())); - - // register requests - Resource capability = YarnCompat.resource(cfg, appConfig.containerMem(), appConfig.containerVCores()); - Priority prio = Priority.newInstance(appConfig.amPriority()); - - for (int i = 0; i < appConfig.containersToAllocate(); i++) { - // TODO: Add allocation (host/rack rules) - and disable location constraints - ContainerRequest req = new ContainerRequest(capability, null, null, prio); - amRpc.addContainerRequest(req); - } - - - // update status every 5 sec - final long heartBeatRate = TimeUnit.SECONDS.toMillis(5); - - // start the allocation loop - // when a new container is allocated, launch it right away - - int responseId = 0; - - try { - do { - AllocateResponse alloc = amRpc.allocate(responseId++); - List currentlyAllocated = alloc.getAllocatedContainers(); - for (Container container : currentlyAllocated) { - launchContainer(container); - allocatedContainers.add(container.getId()); - } - - if (currentlyAllocated.size() > 0) { - int needed = appConfig.containersToAllocate() - allocatedContainers.size(); - if (needed > 0) { - log.info(String.format("%s containers allocated, %s remaining", allocatedContainers.size(), - needed)); - } - else { - log.info(String.format("Fully allocated %s containers", allocatedContainers.size())); - } - } - - List completed = alloc.getCompletedContainersStatuses(); - for (ContainerStatus status : completed) { - if (!completedContainers.contains(status.getContainerId())) { - ContainerId containerId = status.getContainerId(); - completedContainers.add(containerId); - - boolean containerSuccesful = false; - - switch (status.getExitStatus()) { - case ContainerExitStatus.SUCCESS: - log.info(String.format("Container %s finished succesfully...", containerId)); - containerSuccesful = true; - break; - case ContainerExitStatus.ABORTED: - log.warn(String.format("Container %s aborted...", containerId)); - break; - case ContainerExitStatus.DISKS_FAILED: - log.warn(String.format("Container %s ran out of disk...", containerId)); - break; - case ContainerExitStatus.PREEMPTED: - log.warn(String.format("Container %s preempted...", containerId)); - break; - default: - log.warn(String.format("Container %s exited with an invalid/unknown exit code...", containerId)); - } - - if (!containerSuccesful) { - log.warn("Cluster has not completed succesfully..."); - clusterHasFailed = true; - running = false; - } - } - } - - if (completedContainers.size() == appConfig.containersToAllocate()) { - running = false; - } - - if (running) { - try { - Thread.sleep(heartBeatRate); - } catch (Exception ex) { - throw new EsYarnNmException("Cluster interrupted"); - } - } - } while (running); - } finally { - log.info("Cluster has completed running..."); - try { - Thread.sleep(TimeUnit.SECONDS.toMillis(15)); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - close(); - } - } - - private void attemptKeytabLogin() { - if (UserGroupInformation.isSecurityEnabled()) { - try { - String localhost = InetAddress.getLocalHost().getCanonicalHostName(); - String keytabFilename = appConfig.kerberosKeytab(); - if (keytabFilename == null || keytabFilename.length() == 0) { - throw new EsYarnAmException("Security is enabled, but we could not find a configured keytab; Bailing out..."); - } - String configuredPrincipal = appConfig.kerberosPrincipal(); - String principal = SecurityUtil.getServerPrincipal(configuredPrincipal, localhost); - UserGroupInformation.loginUserFromKeytab(principal, keytabFilename); - } catch (UnknownHostException e) { - throw new EsYarnAmException("Could not read localhost information for server principal construction; Bailing out...", e); - } catch (IOException e) { - throw new EsYarnAmException("Could not log in.", e); - } - } - } - - private void launchContainer(Container container) { - ContainerLaunchContext ctx = Records.newRecord(ContainerLaunchContext.class); - - ctx.setEnvironment(setupEnv(appConfig)); - ctx.setLocalResources(setupEsZipResource(appConfig)); - ctx.setCommands(setupEsScript(appConfig)); - - log.info("About to launch container for command: " + ctx.getCommands()); - - // setup container - Map startContainer = nmRpc.startContainer(container, ctx); - log.info("Started container " + container); - } - - private Map setupEnv(Config appConfig) { - // standard Hadoop env setup - Map env = YarnUtils.setupEnv(cfg); - // copy esYarn Config - //env.put(EsYarnConstants.CFG_PROPS, masterEnv.get(EsYarnConstants.CFG_PROPS)); - // plus expand its vars into the env - YarnUtils.addToEnv(env, appConfig.envVars()); - - // add system properties (to ES_JAVA_OPTS for ES to pick them up) - Map sysProps = appConfig.systemProps(); - if (!sysProps.isEmpty()) { - StringBuilder sb = new StringBuilder(); - for (Map.Entry prop : appConfig.systemProps().entrySet()) { - sb.append(String.format(Locale.ROOT, " -D%s=%s", prop.getKey(), prop.getValue())); - } - YarnUtils.addToEnv(env, "ES_JAVA_OPTS", sb.toString()); - } - - return env; - } - - - private Map setupEsZipResource(Config conf) { - // elasticsearch.zip - Map resources = new LinkedHashMap(); - - LocalResource esZip = Records.newRecord(LocalResource.class); - String esZipHdfsPath = conf.esZipHdfsPath(); - Path p = new Path(esZipHdfsPath); - FileStatus fsStat; - try { - fsStat = FileSystem.get(cfg).getFileStatus(p); - } catch (IOException ex) { - throw new IllegalArgumentException( - String.format("Cannot find Elasticsearch zip at [%s]; make sure the artifacts have been properly provisioned and the correct permissions are in place.", esZipHdfsPath), ex); - } - // use the normalized path as otherwise YARN chokes down the line - esZip.setResource(ConverterUtils.getYarnUrlFromPath(fsStat.getPath())); - esZip.setSize(fsStat.getLen()); - esZip.setTimestamp(fsStat.getModificationTime()); - esZip.setType(LocalResourceType.ARCHIVE); - esZip.setVisibility(LocalResourceVisibility.PUBLIC); - - resources.put(conf.esZipName(), esZip); - return resources; - } - - private List setupEsScript(Config conf) { - List cmds = new ArrayList(); - // don't use -jar since it overrides the classpath - cmds.add(YarnCompat.$$(ApplicationConstants.Environment.SHELL)); - // make sure to include the ES.ZIP archive name used in the local resource setup above (since it's the folder where it got unpacked) - cmds.add(conf.esZipName() + "/" + conf.esScript()); - cmds.add("1>" + ApplicationConstants.LOG_DIR_EXPANSION_VAR + "/" + ApplicationConstants.STDOUT); - cmds.add("2>" + ApplicationConstants.LOG_DIR_EXPANSION_VAR + "/" + ApplicationConstants.STDERR); - return Collections.singletonList(StringUtils.concatenate(cmds, " ")); - } - - public boolean hasFailed() { - return clusterHasFailed; - } - - @Override - public void close() { - running = false; - nmRpc.close(); - } -} \ No newline at end of file diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/EsYarnAmException.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/EsYarnAmException.java deleted file mode 100644 index 3d051cc56..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/EsYarnAmException.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.am; - -import org.elasticsearch.hadoop.yarn.EsYarnException; - -public class EsYarnAmException extends EsYarnException { - - public EsYarnAmException() { - } - - public EsYarnAmException(String message, Throwable cause) { - super(message, cause); - } - - public EsYarnAmException(String message) { - super(message); - } - - public EsYarnAmException(Throwable cause) { - super(cause); - } - -} diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/EsYarnNmException.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/EsYarnNmException.java deleted file mode 100644 index fa7477a8c..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/EsYarnNmException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.am; - -import org.elasticsearch.hadoop.yarn.EsYarnException; - -public class EsYarnNmException extends EsYarnException { - - public EsYarnNmException() { - } - - public EsYarnNmException(String message, Throwable cause) { - super(message, cause); - } - - public EsYarnNmException(String message) { - super(message); - } - - public EsYarnNmException(Throwable cause) { - super(cause); - } -} diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/NodeMasterRpc.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/NodeMasterRpc.java deleted file mode 100644 index 710252326..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/am/NodeMasterRpc.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.am; - -import java.nio.ByteBuffer; -import java.util.Map; - -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.yarn.api.records.Container; -import org.apache.hadoop.yarn.api.records.ContainerId; -import org.apache.hadoop.yarn.api.records.ContainerLaunchContext; -import org.apache.hadoop.yarn.api.records.ContainerStatus; -import org.apache.hadoop.yarn.api.records.NodeId; -import org.apache.hadoop.yarn.client.api.NMClient; -import org.apache.hadoop.yarn.client.api.NMTokenCache; -import org.apache.hadoop.yarn.conf.YarnConfiguration; -import org.elasticsearch.hadoop.yarn.compat.YarnCompat; - -class NodeMasterRpc implements AutoCloseable { - - private final Configuration cfg; - private final NMTokenCache tokenCache; - private NMClient client; - - public NodeMasterRpc(Configuration cfg, NMTokenCache tokenCache) { - this.cfg = new YarnConfiguration(cfg); - this.tokenCache = tokenCache; - } - - public void start() { - if (client != null) { - return; - } - - client = NMClient.createNMClient("Elasticsearch-YARN"); - YarnCompat.setNMTokenCache(client, tokenCache); - client.init(cfg); - client.start(); - } - - public Map startContainer(Container container, ContainerLaunchContext containerLaunchContext) { - try { - return client.startContainer(container, containerLaunchContext); - } catch (Exception ex) { - throw new EsYarnNmException(); - } - } - - public ContainerStatus getContainerState(ContainerId containerId, NodeId nodeId) { - try { - return client.getContainerStatus(containerId, nodeId); - } catch (Exception ex) { - throw new EsYarnNmException(); - } - } - - @Override - public void close() { - if (client == null) { - return; - } - - client.stop(); - client = null; - } -} diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/cfg/Config.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/cfg/Config.java deleted file mode 100644 index 309187398..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/cfg/Config.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.cfg; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLDecoder; -import java.util.Enumeration; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Properties; -import java.util.Set; - -import org.elasticsearch.hadoop.yarn.util.Assert; -import org.elasticsearch.hadoop.yarn.util.PropertiesUtils; -import org.elasticsearch.hadoop.yarn.util.StringUtils; - -public class Config { - - private static final String CLIENT_CFG = "cfg.properties"; - private final Properties cfg; - - public Config(Properties props) { - this.cfg = new Properties(PropertiesUtils.load(Config.class, CLIENT_CFG)); - PropertiesUtils.merge(cfg, props); - } - - public String appType() { - return cfg.getProperty("app.type"); - } - - public String appName() { - return cfg.getProperty("app.name"); - } - - public int amPriority() { - return Integer.parseInt(cfg.getProperty("app.priority")); - } - - public String amQueue() { - return cfg.getProperty("app.queue"); - } - - public int amMem() { - return Integer.parseInt(cfg.getProperty("am.mem")); - } - - public int amVCores() { - return Integer.parseInt(cfg.getProperty("am.vcores")); - } - - public Set appTags() { - return new LinkedHashSet(StringUtils.tokenize(cfg.getProperty("app.tags"))); - } - - private String hdfsUploadDir() { - String dir = cfg.getProperty("hdfs.upload.dir"); - return dir.endsWith("/") ? dir : dir + "/"; - } - - public String jarHdfsPath() { - return hdfsUploadDir() + jarName(); - } - - public String jarName() { - return cfg.getProperty("hdfs.es.yarn.jar"); - } - - public String esZipHdfsPath() { - return hdfsUploadDir() + esZipName(); - } - - public String esZipName() { - return "elasticsearch-" + downloadEsVersion() + ".zip"; - } - - public String esScript() { - // the zip contains a folder - // include the zip name plus the folder - return "elasticsearch-" + downloadEsVersion() + "/bin/elasticsearch"; - } - - public int containerPriority() { - return Integer.parseInt(cfg.getProperty("container.priority")); - } - - public int containerMem() { - return Integer.parseInt(cfg.getProperty("container.mem")); - } - - public int containerVCores() { - return Integer.parseInt(cfg.getProperty("container.vcores")); - } - - public int containersToAllocate() { - return Integer.parseInt(cfg.getProperty("containers")); - } - - public String kerberosPrincipal() { - return cfg.getProperty("am.kerberos.principal", System.getProperty("user.name")); - } - - public String kerberosKeytab() { - return cfg.getProperty("am.kerberos.keytab"); - } - - public URL downloadURL() { - String url = cfg.getProperty("download.es.full.url"); - url = (StringUtils.hasText(url) ? url : cfg.getProperty("download.es.url") + esZipName()); - try { - return new URL(url); - } catch (MalformedURLException ex) { - throw new IllegalArgumentException("Invalid URL", ex); - } - } - - public String downloadLocalDir() { - return cfg.getProperty("download.local.dir"); - } - - public String downloadEsVersion() { - return cfg.getProperty("es.version"); - } - - public File downloadedEs() { - String dl = downloadLocalDir(); - if (!dl.endsWith("/")) { - dl = dl + "/"; - } - return new File(dl + esZipName()); - } - - public File downloadedEsYarn() { - // internal property - String jar = cfg.getProperty("internal.es.yarn.file"); - - if (!StringUtils.hasText(jar)) { - Class clazz = getClass(); - // detect jar - ClassLoader loader = clazz.getClassLoader(); - String classFile = clazz.getName().replaceAll("\\.", "/") + ".class"; - try { - for (Enumeration itr = loader.getResources(classFile); itr.hasMoreElements();) { - URL url = itr.nextElement(); - if ("jar".equals(url.getProtocol())) { - String toReturn = url.getPath(); - if (toReturn.startsWith("file:")) { - toReturn = toReturn.substring("file:".length()); - } - toReturn = URLDecoder.decode(toReturn, "UTF-8"); - jar = toReturn.replaceAll("!.*$", ""); - } - } - } catch (IOException ex) { - throw new IllegalStateException("Cannot detect the ES-YARN jar", ex); - } - } - - Assert.hasText(jar, "Es-YARN.jar is not set and could not be detected..."); - return new File(jar); - } - - public Map envVars() { - Map env = new LinkedHashMap(); - Set keys = cfg.stringPropertyNames(); - String prefix = "env."; - for (String key : keys) { - if (key.startsWith(prefix)) { - env.put(key.substring(prefix.length()), cfg.getProperty(key)); - } - } - return env; - } - - public Map systemProps() { - Map sysProp = new LinkedHashMap(); - Set keys = cfg.stringPropertyNames(); - String prefix = "sys.prop."; - for (String key : keys) { - if (key.startsWith(prefix)) { - sysProp.put(key.substring(prefix.length()), cfg.getProperty(key)); - } - } - return sysProp; - } - - public Properties asProperties() { - return PropertiesUtils.merge(null, cfg); - } -} \ No newline at end of file diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/cli/YarnBootstrap.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/cli/YarnBootstrap.java deleted file mode 100644 index 0b16db4b3..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/cli/YarnBootstrap.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.cli; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.text.DateFormat; -import java.util.Date; -import java.util.List; - -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.conf.Configured; -import org.apache.hadoop.fs.FileStatus; -import org.apache.hadoop.fs.FileSystem; -import org.apache.hadoop.fs.FileUtil; -import org.apache.hadoop.fs.Path; -import org.apache.hadoop.util.Tool; -import org.apache.hadoop.util.ToolRunner; -import org.apache.hadoop.yarn.api.records.ApplicationId; -import org.apache.hadoop.yarn.api.records.ApplicationReport; -import org.apache.hadoop.yarn.conf.YarnConfiguration; -import org.apache.hadoop.yarn.webapp.util.WebAppUtils; -import org.elasticsearch.hadoop.yarn.cfg.Config; -import org.elasticsearch.hadoop.yarn.client.ClientRpc; -import org.elasticsearch.hadoop.yarn.client.YarnLauncher; -import org.elasticsearch.hadoop.yarn.util.HttpDownloader; -import org.elasticsearch.hadoop.yarn.util.IOUtils; -import org.elasticsearch.hadoop.yarn.util.PropertiesUtils; - -/** - * Starts the client app, allowing defaults to be overridden. - */ -public class YarnBootstrap extends Configured implements Tool { - - private static String HELP = null; - private Config cfg; - - public static void main(String[] args) throws Exception { - int status = -1; - try { - status = ToolRunner.run(new YarnBootstrap(), args); - } catch (Exception ex) { - System.err.println("Abnormal execution:" + ex.getMessage()); - ex.printStackTrace(System.err); - } - System.exit(status); - } - - private void displayHelp(String message) { - if (message != null) { - System.out.println(message); - } - if (HELP == null) { - HELP = IOUtils.readFrom(getClass().getResourceAsStream("help.txt")); - } - System.out.println(HELP); - } - - @Override - public int run(String[] args) throws Exception { - if (args == null || args.length < 1) { - displayHelp("No command specified"); - return -1; - } - - String cmd = args[0]; - - cfg = new Config(PropertiesUtils.fromCmdLine(args, 1)); - - if ("-download-es".equals(cmd)) { - downloadEs(); - } - else if ("-install".equals(cmd)) { - installEsYarn(); - } - else if ("-install-es".equals(cmd)) { - installEs(); - } - else if ("-help".equals(cmd)) { - displayHelp(null); - } - else if ("-start".equals(cmd)) { - start(); - } - else if ("-status".equals(cmd)) { - status(); - } - else if ("-stop".equals(cmd)) { - stop(); - } - else { - displayHelp("Unknown command specified " + cmd); - return -1; - } - - return 0; - } - - private void downloadEs() { - if (cfg.downloadedEs().exists()) { - System.out.println(String.format("Destination file %s already exists; aborting download...", cfg.downloadedEs())); - return; - } - System.out.println(String.format("Downloading Elasticsearch %s", cfg.downloadEsVersion())); - new HttpDownloader().downloadES(cfg); - } - - private void installEsYarn() { - install(cfg.downloadedEsYarn(), cfg.jarHdfsPath(), getConf()); - } - - private void installEs() { - install(cfg.downloadedEs(), cfg.esZipHdfsPath(), getConf()); - } - - private void install(File src, String dst, Configuration cfg) { - Path target = new Path(dst); - try { - FileSystem fs = FileSystem.get(URI.create("hdfs:///"), cfg); - if (fs.exists(target)) { - fs.delete(target, true); - } - FileUtil.copy(src, fs, target, false, cfg); - FileStatus stats = fs.getFileStatus(target); - System.out.println(String.format("Uploaded %s to HDFS at %s", src.getAbsolutePath(), stats.getPath())); - } catch (IOException ex) { - throw new IllegalStateException(String.format("Cannot upload %s in HDFS at %s", src.getAbsolutePath(), dst), ex); - } - } - - private void start() { - ClientRpc client = new ClientRpc(getConf()); - ApplicationId id = null; - ApplicationReport report = null; - - try { - YarnLauncher launcher = new YarnLauncher(client, cfg); - id = launcher.run(); - report = client.getReport(id); - } finally { - client.close(); - } - - System.out.println(String.format("Launched a %d %s Elasticsearch-YARN cluster [%s@%s] at %tc", - cfg.containersToAllocate(), (cfg.containersToAllocate() > 1 ? "nodes" : "node"), id, report.getTrackingUrl(), report.getStartTime())); - } - - private void stop() { - ClientRpc client = new ClientRpc(getConf()); - client.start(); - try { - List esApps = client.listEsClustersAlive(); - for (ApplicationReport report : esApps) { - System.out.println(String.format("Stopping Elasticsearch-YARN Cluster with id %s", report.getApplicationId())); - } - List apps = client.killEsApps(); - for (ApplicationReport report : apps) { - System.out.println(String.format("Stopped Elasticsearch-YARN Cluster with id %s", report.getApplicationId())); - } - } finally { - client.close(); - } - } - - private void status() { - ClientRpc client = new ClientRpc(getConf()); - client.start(); - List esApps = null; - try { - esApps = client.listEsClusters(); - } finally { - client.close(); - } - System.out.println(buildStatusReport(esApps)); - } - - private String buildStatusReport(List esApps) { - if (esApps.isEmpty()) { - return String.format("No Elasticsearch YARN clusters found at %s, webapp at %s", - getConf().get(YarnConfiguration.RM_ADDRESS), WebAppUtils.getRMWebAppURLWithoutScheme(getConf())); - } - - String columnSeparator = " "; - StringBuilder sb = new StringBuilder(); - // header - sb.append("Id "); - sb.append(columnSeparator); - sb.append("State "); - sb.append(columnSeparator); - sb.append("Status "); - sb.append(columnSeparator); - sb.append("Start Time "); - sb.append(columnSeparator); - sb.append("Finish Time "); - sb.append(columnSeparator); - sb.append("Tracking URL"); - sb.append("\n"); - - DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); - - for (ApplicationReport appReport : esApps) { - sb.append(appReport.getApplicationId()); - sb.append(columnSeparator); - sb.append(box(appReport.getYarnApplicationState().toString(), 10)); - sb.append(columnSeparator); - sb.append(box(appReport.getFinalApplicationStatus().toString(), 9)); - sb.append(columnSeparator); - long date = appReport.getStartTime(); - sb.append(date == 0 ? "N/A " : box(dateFormat.format(new Date(date)), 17)); - sb.append(columnSeparator); - date = appReport.getFinishTime(); - sb.append(date == 0 ? "N/A " : box(dateFormat.format(new Date(date)), 17)); - sb.append(columnSeparator); - sb.append(appReport.getTrackingUrl()); - sb.append(columnSeparator); - sb.append("\n"); - } - - return sb.toString(); - } - - // add the string to the box and fill it (with spaces) until it reaches its limit - private String box(String string, int limit) { - StringBuilder sb = new StringBuilder(string); - for (int i = sb.length(); i < limit; i++) { - sb.append(" "); - } - return sb.toString(); - } -} \ No newline at end of file diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/client/ClientRpc.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/client/ClientRpc.java deleted file mode 100644 index eb7ccac15..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/client/ClientRpc.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.client; - -import java.util.Collections; -import java.util.EnumSet; -import java.util.List; -import java.util.Set; - -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.security.UserGroupInformation; -import org.apache.hadoop.yarn.api.records.ApplicationId; -import org.apache.hadoop.yarn.api.records.ApplicationReport; -import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext; -import org.apache.hadoop.yarn.api.records.YarnApplicationState; -import org.apache.hadoop.yarn.client.api.YarnClient; -import org.apache.hadoop.yarn.client.api.YarnClientApplication; -import org.apache.hadoop.yarn.conf.YarnConfiguration; -import org.elasticsearch.hadoop.yarn.EsYarnException; -import org.elasticsearch.hadoop.yarn.util.YarnUtils; - -public class ClientRpc implements AutoCloseable { - - private static final Set ES_TYPE = Collections.singleton("ELASTICSEARCH"); - private static final EnumSet ALIVE = EnumSet.range(YarnApplicationState.NEW, YarnApplicationState.RUNNING); - - private YarnClient client; - private final Configuration cfg; - - public ClientRpc(Configuration cfg) { - this.cfg = new YarnConfiguration(cfg); - } - - public void start() { - if (client != null) { - return; - } - - UserGroupInformation.setConfiguration(cfg); - - client = YarnClient.createYarnClient(); - client.init(cfg); - client.start(); - } - - public YarnClientApplication newApp() { - try { - return client.createApplication(); - } catch (Exception ex) { - throw new EsYarnException(ex); - } - } - - public ApplicationId submitApp(ApplicationSubmissionContext appContext) { - try { - return client.submitApplication(appContext); - } catch (Exception ex) { - throw new EsYarnException(ex); - } - } - - public List killEsApps() { - try { - List esApps = client.getApplications(ES_TYPE, ALIVE); - - for (ApplicationReport appReport : esApps) { - client.killApplication(appReport.getApplicationId()); - } - - return esApps; - } catch (Exception ex) { - throw new EsYarnException(ex); - } - } - - public void killApp(String appId) { - try { - client.killApplication(YarnUtils.createAppIdFrom(appId)); - } catch (Exception ex) { - throw new EsYarnException(ex); - } - } - - public ApplicationReport getReport(ApplicationId appId) { - try { - return client.getApplicationReport(appId); - } catch (Exception ex) { - throw new EsYarnException(ex); - } - } - - public List listApps() { - try { - return client.getApplications(); - } catch (Exception ex) { - throw new EsYarnException(ex); - } - } - - - public List listEsClusters() { - try { - return client.getApplications(ES_TYPE); - } catch (Exception ex) { - throw new EsYarnException(ex); - } - } - - public List listEsClustersAlive() { - try { - return client.getApplications(ES_TYPE, ALIVE); - } catch (Exception ex) { - throw new EsYarnException(ex); - } - } - - public void waitForApp(ApplicationId appId, long timeout) { - boolean repeat = false; - long start = System.currentTimeMillis(); - do { - try { - ApplicationReport appReport = client.getApplicationReport(appId); - YarnApplicationState appState = appReport.getYarnApplicationState(); - repeat = (appState != YarnApplicationState.FINISHED && appState != YarnApplicationState.KILLED && appState != YarnApplicationState.FAILED); - if (repeat) { - Thread.sleep(500); - } - } catch (Exception ex) { - throw new EsYarnException(ex); - } - } while (repeat && (System.currentTimeMillis() - start) < timeout); - } - - @Override - public void close() { - if (client != null) { - client.stop(); - client = null; - } - } - - public Configuration getConfiguration() { - return cfg; - } -} \ No newline at end of file diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/client/YarnLauncher.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/client/YarnLauncher.java deleted file mode 100644 index 4dde8f9b8..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/client/YarnLauncher.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.client; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.fs.FileStatus; -import org.apache.hadoop.fs.FileSystem; -import org.apache.hadoop.fs.Path; -import org.apache.hadoop.yarn.api.ApplicationConstants; -import org.apache.hadoop.yarn.api.records.ApplicationId; -import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext; -import org.apache.hadoop.yarn.api.records.ContainerLaunchContext; -import org.apache.hadoop.yarn.api.records.LocalResource; -import org.apache.hadoop.yarn.api.records.LocalResourceType; -import org.apache.hadoop.yarn.api.records.LocalResourceVisibility; -import org.apache.hadoop.yarn.api.records.Priority; -import org.apache.hadoop.yarn.client.api.YarnClientApplication; -import org.apache.hadoop.yarn.util.ConverterUtils; -import org.apache.hadoop.yarn.util.Records; -import org.elasticsearch.hadoop.yarn.EsYarnConstants; -import org.elasticsearch.hadoop.yarn.am.ApplicationMaster; -import org.elasticsearch.hadoop.yarn.cfg.Config; -import org.elasticsearch.hadoop.yarn.compat.YarnCompat; -import org.elasticsearch.hadoop.yarn.util.PropertiesUtils; -import org.elasticsearch.hadoop.yarn.util.StringUtils; -import org.elasticsearch.hadoop.yarn.util.YarnUtils; - -public class YarnLauncher { - - private static final Log log = LogFactory.getLog(YarnLauncher.class); - - private final ClientRpc client; - private Config clientCfg; - - public YarnLauncher(ClientRpc client, Config cfg) { - this.client = client; - this.clientCfg = cfg; - } - - public ApplicationId run() { - client.start(); - - YarnClientApplication app = client.newApp(); - ApplicationSubmissionContext am = setupAM(app); - ApplicationId appId = client.submitApp(am); - return am.getApplicationId(); - } - - private ApplicationSubmissionContext setupAM(YarnClientApplication clientApp) { - ApplicationSubmissionContext appContext = clientApp.getApplicationSubmissionContext(); - // already happens inside Hadoop but to be consistent - appContext.setApplicationId(clientApp.getNewApplicationResponse().getApplicationId()); - appContext.setApplicationName(clientCfg.appName()); - appContext.setAMContainerSpec(createContainerContext()); - appContext.setResource(YarnCompat.resource(client.getConfiguration(), clientCfg.amMem(), clientCfg.amVCores())); - appContext.setPriority(Priority.newInstance(clientCfg.amPriority())); - appContext.setQueue(clientCfg.amQueue()); - appContext.setApplicationType(clientCfg.appType()); - YarnCompat.setApplicationTags(appContext, clientCfg.appTags()); - - return appContext; - } - - private ContainerLaunchContext createContainerContext() { - ContainerLaunchContext amContainer = Records.newRecord(ContainerLaunchContext.class); - - amContainer.setLocalResources(setupEsYarnJar()); - amContainer.setEnvironment(setupEnv()); - amContainer.setCommands(setupCmd()); - - return amContainer; - } - - private Map setupEsYarnJar() { - Map resources = new LinkedHashMap(); - LocalResource esYarnJar = Records.newRecord(LocalResource.class); - Path p = new Path(clientCfg.jarHdfsPath()); - FileStatus fsStat; - try { - fsStat = FileSystem.get(client.getConfiguration()).getFileStatus(p); - } catch (IOException ex) { - throw new IllegalArgumentException( - String.format("Cannot find jar [%s]; make sure the artifacts have been properly provisioned and the correct permissions are in place.", clientCfg.jarHdfsPath()), ex); - } - // use the normalized path as otherwise YARN chokes down the line - esYarnJar.setResource(ConverterUtils.getYarnUrlFromPath(fsStat.getPath())); - esYarnJar.setSize(fsStat.getLen()); - esYarnJar.setTimestamp(fsStat.getModificationTime()); - esYarnJar.setType(LocalResourceType.FILE); - esYarnJar.setVisibility(LocalResourceVisibility.PUBLIC); - - resources.put(clientCfg.jarName(), esYarnJar); - return resources; - } - - private Map setupEnv() { - Configuration cfg = client.getConfiguration(); - - Map env = YarnUtils.setupEnv(cfg); - YarnUtils.addToEnv(env, EsYarnConstants.CFG_PROPS, PropertiesUtils.propsToBase64(clientCfg.asProperties())); - YarnUtils.addToEnv(env, clientCfg.envVars()); - - return env; - } - - private List setupCmd() { - List cmds = new ArrayList(); - // don't use -jar since it overrides the classpath - cmds.add(YarnCompat.$$(ApplicationConstants.Environment.JAVA_HOME) + "/bin/java"); - cmds.add(ApplicationMaster.class.getName()); - cmds.add("1>" + ApplicationConstants.LOG_DIR_EXPANSION_VAR + "/" + ApplicationConstants.STDOUT); - cmds.add("2>" + ApplicationConstants.LOG_DIR_EXPANSION_VAR + "/" + ApplicationConstants.STDERR); - return Collections.singletonList(StringUtils.concatenate(cmds, " ")); - } -} \ No newline at end of file diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/compat/YarnCompat.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/compat/YarnCompat.java deleted file mode 100644 index a6fda32e3..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/compat/YarnCompat.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.compat; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Set; - -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.yarn.api.ApplicationConstants; -import org.apache.hadoop.yarn.api.ApplicationConstants.Environment; -import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext; -import org.apache.hadoop.yarn.api.records.Resource; -import org.apache.hadoop.yarn.client.api.AMRMClient; -import org.apache.hadoop.yarn.client.api.NMClient; -import org.apache.hadoop.yarn.client.api.NMTokenCache; -import org.apache.hadoop.yarn.conf.YarnConfiguration; -import org.apache.hadoop.yarn.util.Records; -import org.elasticsearch.hadoop.yarn.util.ReflectionUtils; -import org.elasticsearch.hadoop.yarn.util.YarnUtils; - -/** - * Series of compatibility utils around YARN classes... - */ -public abstract class YarnCompat { - - // introduced in 2.4 (not 2.2 which might be used in some distros) - private static String[] DEFAULT_PLATFORM_APPLICATION_CLASSPATH; - private static String CLASS_PATH_SEPARATOR; - - private static final Method NMCLIENT_SET_TOKEN_CACHE; - private static final Method AMRMCLIENT_SET_TOKEN_CACHE; - private static final Method ENVIRONMENT_$$; - private static final Method SET_VIRTUAL_CORES; - private static final Method APP_SUBMISSION_CTX; - - - static { - SET_VIRTUAL_CORES = ReflectionUtils.findMethod(Resource.class, "setVirtualCores", int.class); - NMCLIENT_SET_TOKEN_CACHE = ReflectionUtils.findMethod(NMClient.class, "setNMTokenCache", NMTokenCache.class); - AMRMCLIENT_SET_TOKEN_CACHE = ReflectionUtils.findMethod(AMRMClient.class, "setNMTokenCache", NMTokenCache.class); - ENVIRONMENT_$$ = ReflectionUtils.findMethod(Environment.class, "$$", (Class[]) null); - APP_SUBMISSION_CTX = ReflectionUtils.findMethod(ApplicationSubmissionContext.class, "setApplicationTags", Set.class); - } - - // set virtual cores is not available on all Hadoop 2.x distros - public static void setVirtualCores(Configuration cfg, Resource resource, int vCores) { - if (SET_VIRTUAL_CORES != null) { - ReflectionUtils.invoke(SET_VIRTUAL_CORES, resource, YarnUtils.minVCores(cfg, vCores)); - } - } - - public static Resource resource(Configuration cfg, int memory, int cores) { - Resource resource = Records.newRecord(Resource.class); - resource.setMemory(YarnUtils.minMemory(cfg, memory)); - setVirtualCores(cfg, resource, cores); - return resource; - } - - public static String[] DEFAULT_PLATFORM_APPLICATION_CLASSPATH() { - if (DEFAULT_PLATFORM_APPLICATION_CLASSPATH == null) { - Field field = ReflectionUtils.findField(YarnConfiguration.class, "DEFAULT_YARN_CROSS_PLATFORM_APPLICATION_CLASSPATH"); - if (field != null) { - ReflectionUtils.makeAccessible(field); - DEFAULT_PLATFORM_APPLICATION_CLASSPATH = ReflectionUtils.getField(field, null); - } - else { - DEFAULT_PLATFORM_APPLICATION_CLASSPATH = YarnConfiguration.DEFAULT_YARN_APPLICATION_CLASSPATH; - } - } - - return DEFAULT_PLATFORM_APPLICATION_CLASSPATH; - } - - public static String CLASS_PATH_SEPARATOR() { - if (CLASS_PATH_SEPARATOR == null) { - Field field = ReflectionUtils.findField(ApplicationConstants.class, "CLASS_PATH_SEPARATOR"); - if (field != null) { - ReflectionUtils.makeAccessible(field); - CLASS_PATH_SEPARATOR = ReflectionUtils.getField(field, null); - } - else { - // always use the *Nix separator since the chances the server runs on it are significantly higher than on Windows - CLASS_PATH_SEPARATOR = ":"; - } - } - - return CLASS_PATH_SEPARATOR; - } - - public static void setNMTokenCache(AMRMClient client, NMTokenCache tokenCache) { - if (AMRMCLIENT_SET_TOKEN_CACHE != null) { - ReflectionUtils.invoke(AMRMCLIENT_SET_TOKEN_CACHE, client, tokenCache); - } - } - - public static void setNMTokenCache(NMClient client, NMTokenCache tokenCache) { - if (NMCLIENT_SET_TOKEN_CACHE != null) { - ReflectionUtils.invoke(NMCLIENT_SET_TOKEN_CACHE, client, tokenCache); - } - } - - public static String $$(Environment env) { - if (ENVIRONMENT_$$ != null) { - return ReflectionUtils.invoke(ENVIRONMENT_$$, env, (Object[]) null); - } - else { - // prefer *nix separator - return "$" + env.name(); - } - } - - public static void setApplicationTags(ApplicationSubmissionContext appContext, Set appTags) { - if (APP_SUBMISSION_CTX != null) { - ReflectionUtils.invoke(APP_SUBMISSION_CTX, appContext, appTags); - } - } -} \ No newline at end of file diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/rpc/YarnRpc.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/rpc/YarnRpc.java deleted file mode 100644 index 845e1398c..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/rpc/YarnRpc.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.rpc; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.security.PrivilegedAction; - -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.security.UserGroupInformation; -import org.apache.hadoop.yarn.conf.YarnConfiguration; -import org.apache.hadoop.yarn.ipc.YarnRPC; -import org.elasticsearch.hadoop.yarn.EsYarnException; - -/** - * Base class handling the creation of various RPC protocols in YARN. - * - * While for Client protocol there's YarnClient, Application and Container protocols - * do not have such an utility hence the reason for this class to handle the creation - * and disposable in a sane way. - * - * @param

Protocol class - */ -public abstract class YarnRpc

implements AutoCloseable { - - private Class

protocolType; - private Configuration cfg; - private InetSocketAddress endpoint; - - private P proxy; - - public YarnRpc(Class

protocolType, Configuration cfg) { - this.protocolType = protocolType; - // make a copy to avoid the security credentials spilling to the main configuration - this.cfg = new YarnConfiguration(cfg); - } - - public void start() { - // handle security - if (UserGroupInformation.isSecurityEnabled()) { - UserGroupInformation.setConfiguration(cfg); - } - - try { - endpoint = resolveEndpoint(cfg); - } catch (IOException ex) { - throw new EsYarnException("Cannot resolve endpoint", ex); - } - - UserGroupInformation ugi = null; - try { - ugi = UserGroupInformation.getCurrentUser(); - } catch (IOException ex) { - throw new EsYarnException("Cannot get current user", ex); - } - - // create proxy - proxy = ugi.doAs(new PrivilegedAction

() { - @SuppressWarnings("unchecked") - @Override - public P run() { - return (P) YarnRPC.create(cfg).getProxy(protocolType, endpoint, cfg); - } - }); - - } - - protected P proxy() { - return proxy; - } - - @Override - public void close() { - //potentially use RPC.stopProxy(proxy); - YarnRPC.create(cfg).stopProxy(proxy, cfg); - } - - protected abstract InetSocketAddress resolveEndpoint(Configuration cfg) throws IOException; -} diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/Assert.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/Assert.java deleted file mode 100644 index 976c7a842..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/Assert.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.util; - - -/** - * Assertion utility used for validating arguments. - */ -public abstract class Assert { - - public static void hasText(CharSequence sequence, String message) { - if (!StringUtils.hasText(sequence)) { - throw new IllegalArgumentException(message); - } - } - - public static void hasText(CharSequence sequence) { - hasText(sequence, "[Assertion failed] - this CharSequence argument must have text; it must not be null, empty, or blank"); - } - - public static void notNull(Object object, String message) { - if (object == null) { - throw new IllegalArgumentException(message); - } - } - - public static void notNull(Object object) { - notNull(object, "[Assertion failed] - this argument is required; it must not be null"); - } - - public static void isTrue(Boolean object, String message) { - if (!Boolean.TRUE.equals(object)) { - throw new IllegalArgumentException(message); - } - } - - public static void isTrue(Boolean object) { - isTrue(object, "[Assertion failed] - this argument must be true"); - } -} diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/HttpDownloader.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/HttpDownloader.java deleted file mode 100644 index 04b0acc05..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/HttpDownloader.java +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.util; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLConnection; -import java.util.concurrent.TimeUnit; - -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import org.elasticsearch.hadoop.yarn.cfg.Config; - -// Taken from Elasticsearch core -public class HttpDownloader { - - private boolean useTimestamp = false; - private boolean skipExisting = false; - - public HttpDownloader() { - - TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { - public java.security.cert.X509Certificate[] getAcceptedIssuers() { - return null; - } - - public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { - } - - public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { - } - } }; - - // Install the all-trusting trust manager - try { - SSLContext sc = SSLContext.getInstance("TLS"); - sc.init(null, trustAllCerts, new java.security.SecureRandom()); - HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public boolean downloadES(Config cfg) { - return download(cfg.downloadURL(), cfg.downloadedEs(), new VerboseProgress(System.out), TimeUnit.MINUTES.toMillis(15)); - } - - public boolean download(URL source, File dest, DownloadProgress progress, long timeout) { - - if (dest.exists() && skipExisting) { - return true; - } - - //don't do any progress, unless asked - if (progress == null) { - progress = new NullProgress(); - } - - //set the timestamp to the file date. - long timestamp = 0; - - boolean hasTimestamp = false; - if (useTimestamp && dest.exists()) { - timestamp = dest.lastModified(); - hasTimestamp = true; - } - - // create file if needed - if (!dest.exists()) { - try { - File parent = dest.getAbsoluteFile().getParentFile(); - parent.mkdirs(); - dest.createNewFile(); - } catch (IOException ex) { - throw new IllegalStateException(String.format("Cannot write file %s", dest), ex); - } - } - - GetThread getThread = new GetThread(source, dest, hasTimestamp, timestamp, progress); - - try { - getThread.setDaemon(true); - getThread.start(); - getThread.join(timeout); - - if (getThread.isAlive()) { - throw new IllegalStateException("The GET operation took longer than " + timeout + ", stopping it."); - } - } catch (InterruptedException ie) { - return false; - } finally { - getThread.closeStreams(); - } - - return getThread.wasSuccessful(); - } - - public interface DownloadProgress { - void beginDownload(); - - void onTick(); - - void endDownload(); - } - - public static class NullProgress implements DownloadProgress { - - public void beginDownload() { - - } - - public void onTick() { - } - - public void endDownload() { - - } - } - - public static class VerboseProgress implements DownloadProgress { - private int dots = 0; - PrintStream out; - - public VerboseProgress(PrintStream out) { - this.out = out; - } - - public void beginDownload() { - out.print("Downloading "); - dots = 0; - } - - public void onTick() { - out.print("."); - if (dots++ > 50) { - out.flush(); - dots = 0; - } - } - - public void endDownload() { - out.println("DONE"); - out.flush(); - } - } - - private class GetThread extends Thread { - - private final URL source; - private final File dest; - private final boolean hasTimestamp; - private final long timestamp; - private final DownloadProgress progress; - - private boolean success = false; - private RuntimeException ioexception = null; - private InputStream is = null; - private OutputStream os = null; - private URLConnection connection; - private int redirections = 0; - - GetThread(URL source, File dest, boolean h, long t, DownloadProgress p) { - this.source = source; - this.dest = dest; - hasTimestamp = h; - timestamp = t; - progress = p; - } - - public void run() { - try { - success = get(); - } catch (IOException ioex) { - ioexception = new IllegalStateException(ioex); - } - } - - private boolean get() throws IOException { - - connection = openConnection(source); - - if (connection == null) { - return false; - } - - boolean downloadSucceeded = downloadFile(); - - //if (and only if) the use file time option is set, then - //the saved file now has its timestamp set to that of the - //downloaded file - if (downloadSucceeded && useTimestamp) { - updateTimeStamp(); - } - - return downloadSucceeded; - } - - - private boolean redirectionAllowed(URL aSource, URL aDest) throws IOException { - - redirections++; - if (redirections > 5) { - String message = "More than " + 5 + " times redirected, giving up"; - throw new IOException(message); - } - - - return true; - } - - private URLConnection openConnection(URL aSource) throws IOException { - - // set up the URL connection - URLConnection connection = aSource.openConnection(); - // modify the headers - // NB: things like user authentication could go in here too. - if (hasTimestamp) { - connection.setIfModifiedSince(timestamp); - } - - if (connection instanceof HttpURLConnection) { - ((HttpURLConnection) connection).setInstanceFollowRedirects(false); - ((HttpURLConnection) connection).setUseCaches(true); - ((HttpURLConnection) connection).setConnectTimeout(5000); - } - // connect to the remote site (may take some time) - connection.connect(); - - // First check on a 301 / 302 (moved) response (HTTP only) - if (connection instanceof HttpURLConnection) { - HttpURLConnection httpConnection = (HttpURLConnection) connection; - int responseCode = httpConnection.getResponseCode(); - if (responseCode == HttpURLConnection.HTTP_MOVED_PERM - || responseCode == HttpURLConnection.HTTP_MOVED_TEMP - || responseCode == HttpURLConnection.HTTP_SEE_OTHER) { - String newLocation = httpConnection.getHeaderField("Location"); - String message = aSource - + (responseCode == HttpURLConnection.HTTP_MOVED_PERM ? " permanently" : "") + " moved to " - + newLocation; - URL newURL = new URL(newLocation); - if (!redirectionAllowed(aSource, newURL)) { - return null; - } - return openConnection(newURL); - } - // next test for a 304 result (HTTP only) - long lastModified = httpConnection.getLastModified(); - if (responseCode == HttpURLConnection.HTTP_NOT_MODIFIED - || (lastModified != 0 && hasTimestamp && timestamp >= lastModified)) { - // not modified so no file download. just return - // instead and trace out something so the user - // doesn't think that the download happened when it - // didn't - return null; - } - // test for 401 result (HTTP only) - if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { - String message = "HTTP Authorization failure"; - throw new IOException(message); - } - } - - //REVISIT: at this point even non HTTP connections may - //support the if-modified-since behaviour -we just check - //the date of the content and skip the write if it is not - //newer. Some protocols (FTP) don't include dates, of - //course. - return connection; - } - - private boolean downloadFile() throws FileNotFoundException, IOException { - IOException lastEx = null; - for (int i = 0; i < 3; i++) { - // this three attempt trick is to get round quirks in different - // Java implementations. Some of them take a few goes to bind - // property; we ignore the first couple of such failures. - try { - is = connection.getInputStream(); - break; - } catch (IOException ex) { - lastEx = ex; - } - } - if (is == null) { - throw new IOException("Can't get " + source + " to " + dest, lastEx); - } - - os = new FileOutputStream(dest); - progress.beginDownload(); - boolean finished = false; - try { - byte[] buffer = new byte[1024 * 512]; - int length; - while (!isInterrupted() && (length = is.read(buffer)) >= 0) { - os.write(buffer, 0, length); - progress.onTick(); - } - finished = !isInterrupted(); - } finally { - if (!finished) { - // we have started to (over)write dest, but failed. - // Try to delete the garbage we'd otherwise leave - // behind. - IOUtils.close(os); - IOUtils.close(is); - dest.delete(); - } - else { - IOUtils.close(os); - IOUtils.close(is); - } - } - progress.endDownload(); - return true; - } - - private void updateTimeStamp() { - long remoteTimestamp = connection.getLastModified(); - if (remoteTimestamp != 0) { - dest.setLastModified(remoteTimestamp); - } - } - - boolean wasSuccessful() { - if (ioexception != null) { - throw ioexception; - } - return success; - } - - void closeStreams() { - interrupt(); - if (success) { - IOUtils.close(is); - IOUtils.close(os); - } - else { - IOUtils.close(is); - IOUtils.close(os); - if (dest != null && dest.exists()) { - dest.delete(); - } - } - } - } -} \ No newline at end of file diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/IOUtils.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/IOUtils.java deleted file mode 100644 index 69290562b..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/IOUtils.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.util; - -import java.io.BufferedReader; -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.Charset; - -public abstract class IOUtils { - - public static String readFrom(InputStream stream) { - try { - StringBuilder sb = new StringBuilder(); - BufferedReader br = new BufferedReader(new InputStreamReader(stream, Charset.forName("UTF-8"))); - String line; - - while ((line = br.readLine()) != null) { - sb.append(line); - sb.append("\n"); - } - return sb.toString(); - } catch (IOException ex) { - throw new IllegalStateException("Cannot read data stream", ex); - } finally { - try { - stream.close(); - } catch (IOException ex) { - // ignore - } - } - } - - - public static void close(Closeable closable) { - if (closable != null) { - try { - closable.close(); - } catch (IOException e) { - // silently ignore - } - } - } -} diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/PropertiesUtils.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/PropertiesUtils.java deleted file mode 100644 index 265a969f1..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/PropertiesUtils.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.util; - -import java.io.ByteArrayInputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringWriter; -import java.net.URL; -import java.util.Properties; -import java.util.Set; - -import javax.xml.bind.DatatypeConverter; - -public abstract class PropertiesUtils { - - public static Properties load(Class clazz, String cfgName) { - try { - InputStream stream = clazz.getResourceAsStream(cfgName); - Properties props = new Properties(); - props.load(stream); - return props; - } catch (Exception ex) { - throw new IllegalStateException("Cannot find/load file " + cfgName, ex); - } - } - - public static Properties merge(Properties target, Properties other) { - if (target == null) { - target = new Properties(); - } - - if (other == null || other.isEmpty()) { - return target; - } - - Set propertyNames = other.stringPropertyNames(); - - for (String prop : propertyNames) { - target.setProperty(prop, other.getProperty(prop)); - } - - return target; - } - - public static Properties fromCmdLine(String[] args, int offset) { - Properties prop = new Properties(); - - String loadCfg = "loadConfig"; - - for (int i = offset; i < args.length; i++) { - String[] strings = args[i].split("="); - if (strings.length != 2) { - throw new IllegalArgumentException(String.format("Invalid argument %s", args[i])); - } - if (loadCfg.equals(strings[0])) { - merge(prop, load(strings[1])); - } - prop.setProperty(strings[0], strings[1]); - } - return prop; - } - - private static Properties load(String string) { - Properties prop = new Properties(); - try { - InputStream in = (string.contains(":") ? new URL(string).openStream() : new FileInputStream(string)); - prop.load(in); - } catch (IOException ex) { - throw new IllegalArgumentException(String.format("Cannot open source %s", string), ex); - } - return prop; - } - - public static String propsToBase64(Properties props) { - StringWriter sw = new StringWriter(); - if (props != null) { - try { - props.store(sw, ""); - } catch (IOException ex) { - throw new IllegalArgumentException(ex); - } - } - return DatatypeConverter.printBase64Binary(sw.toString().getBytes(StringUtils.UTF_8)); - } - - public static Properties propsFromBase64String(String source) { - Properties copy = new Properties(); - if (source != null) { - try { - copy.load(new InputStreamReader(new ByteArrayInputStream(DatatypeConverter.parseBase64Binary(source)), StringUtils.UTF_8)); - } catch (IOException ex) { - throw new IllegalArgumentException(ex); - } - } - return copy; - } -} \ No newline at end of file diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/ReflectionUtils.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/ReflectionUtils.java deleted file mode 100644 index bb5deb92e..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/ReflectionUtils.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.util; - -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Arrays; - -public abstract class ReflectionUtils { - - public static Field findField(Class clazz, String name) { - return findField(clazz, name, null); - } - - public static Field findField(Class clazz, String name, Class type) { - Assert.notNull(clazz, "Class must not be null"); - Assert.isTrue(name != null || type != null, "Either name or type of the field must be specified"); - Class searchType = clazz; - while (!Object.class.equals(searchType) && searchType != null) { - Field[] fields = searchType.getDeclaredFields(); - for (Field field : fields) { - if ((name == null || name.equals(field.getName())) && (type == null || type.equals(field.getType()))) { - return field; - } - } - searchType = searchType.getSuperclass(); - } - return null; - } - - @SuppressWarnings("unchecked") - public static T getField(Field field, Object target) { - try { - return (T) field.get(target); - } catch (IllegalAccessException ex) { - throw new IllegalStateException("Unexpected reflection exception - " + ex.getClass().getName() + ": "+ ex.getMessage()); - } - } - - public static void setField(Field field, Object target, Object value) { - try { - field.set(target, value); - } catch (IllegalAccessException ex) { - throw new IllegalStateException("Unexpected reflection exception - " + ex.getClass().getName() + ": "+ ex.getMessage()); - } - } - - public static void makeAccessible(AccessibleObject accessible) { - if (!accessible.isAccessible()) { - accessible.setAccessible(true); - } - } - - public static Method findMethod(Class targetClass, String name, Class... paramTypes) { - while (targetClass != null) { - Method[] methods = (targetClass.isInterface() ? targetClass.getMethods() : targetClass.getDeclaredMethods()); - for (Method method : methods) { - if (name.equals(method.getName()) && (paramTypes == null || Arrays.equals(paramTypes, method.getParameterTypes()))) { - return method; - } - } - targetClass = targetClass.getSuperclass(); - } - return null; - } - - @SuppressWarnings("unchecked") - public static T invoke(Method method, Object target, Object...args) { - try { - return (T) method.invoke(target, args); - } catch (Exception ex) { - throw new IllegalArgumentException("Cannot invoke method " + method, ex); - } - } -} \ No newline at end of file diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/StringUtils.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/StringUtils.java deleted file mode 100644 index 19a09ad41..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/StringUtils.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.util; - -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.StringTokenizer; - - -/** - * Utility class around Strings. Used to remove dependency on other libraries that might (or not) be available at runtime. - */ -public abstract class StringUtils { - - public static final Charset UTF_8 = Charset.forName("UTF-8"); - public static final String EMPTY = ""; - - public static boolean hasLength(CharSequence sequence) { - return (sequence != null && sequence.length() > 0); - } - - public static boolean hasText(CharSequence sequence) { - if (!hasLength(sequence)) { - return false; - } - int length = sequence.length(); - for (int i = 0; i < length; i++) { - if (!Character.isWhitespace(sequence.charAt(i))) { - return true; - } - } - return false; - } - - public static List tokenize(String string) { - return tokenize(string, ","); - } - - public static List tokenize(String string, String delimiters) { - return tokenize(string, delimiters, true, true); - } - - public static List tokenize(String string, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) { - if (string == null) { - return Collections.emptyList(); - } - StringTokenizer st = new StringTokenizer(string, delimiters); - List tokens = new ArrayList(); - while (st.hasMoreTokens()) { - String token = st.nextToken(); - if (trimTokens) { - token = token.trim(); - } - if (!ignoreEmptyTokens || token.length() > 0) { - tokens.add(token); - } - } - return tokens; - } - - public static String concatenate(Collection list, String delimiter) { - if (list == null || list.isEmpty()) { - return EMPTY; - } - if (delimiter == null) { - delimiter = EMPTY; - } - StringBuilder sb = new StringBuilder(); - - for (Object object : list) { - sb.append(object.toString()); - sb.append(delimiter); - } - - sb.setLength(sb.length() - delimiter.length()); - return sb.toString(); - } - - public static String concatenate(Object[] array, String delimiter) { - if (array == null || array.length == 0) { - return EMPTY; - } - if (delimiter == null) { - delimiter = EMPTY; - } - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < array.length; i++) { - if (i > 0) { - sb.append(delimiter); - } - sb.append(array[i]); - } - return sb.toString(); - } - - public static String deleteWhitespace(CharSequence sequence) { - if (!hasLength(sequence)) { - return EMPTY; - } - - StringBuilder sb = new StringBuilder(sequence.length()); - for (int i = 0; i < sequence.length(); i++) { - char currentChar = sequence.charAt(i); - if (!Character.isWhitespace(currentChar)) { - sb.append(currentChar); - } - } - // return the initial String if no whitespace is found - return (sb.length() == sequence.length() ? sequence.toString() : sb.toString()); - } - - public static boolean isLowerCase(CharSequence string) { - for (int index = 0; index < string.length(); index++) { - if (Character.isUpperCase(string.charAt(index))) { - return false; - } - } - return true; - } -} \ No newline at end of file diff --git a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/YarnUtils.java b/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/YarnUtils.java deleted file mode 100644 index 6e7338621..000000000 --- a/yarn/src/main/java/org/elasticsearch/hadoop/yarn/util/YarnUtils.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.hadoop.yarn.util; - -import java.net.InetSocketAddress; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.fs.FileSystem; -import org.apache.hadoop.yarn.api.ApplicationConstants; -import org.apache.hadoop.yarn.api.ApplicationConstants.Environment; -import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; -import org.apache.hadoop.yarn.api.records.ApplicationId; -import org.apache.hadoop.yarn.api.records.ContainerId; -import org.apache.hadoop.yarn.conf.YarnConfiguration; -import org.apache.hadoop.yarn.util.ConverterUtils; -import org.elasticsearch.hadoop.yarn.EsYarnConstants; -import org.elasticsearch.hadoop.yarn.compat.YarnCompat; - -import static org.apache.hadoop.yarn.conf.YarnConfiguration.*; - -public abstract class YarnUtils { - - public static ApplicationAttemptId getApplicationAttemptId(Map env) { - if (env == null) { - return null; - } - String amContainerId = env.get(ApplicationConstants.Environment.CONTAINER_ID.name()); - if (amContainerId == null) { - return null; - } - ContainerId containerId = ConverterUtils.toContainerId(amContainerId); - return containerId.getApplicationAttemptId(); - } - - public static InetSocketAddress getResourceManagerAddr(Configuration cfg) { - return cfg.getSocketAddr(RM_SCHEDULER_ADDRESS, DEFAULT_RM_SCHEDULER_ADDRESS, DEFAULT_RM_SCHEDULER_PORT); - } - - public static long getAmHeartBeatRate(Configuration cfg) { - return cfg.getLong(RM_AM_EXPIRY_INTERVAL_MS, DEFAULT_RM_AM_EXPIRY_INTERVAL_MS); - } - - public static Map setupEnv(Configuration cfg) { - Map env = new LinkedHashMap(); // System.getenv() - // add Hadoop Classpath - for (String c : cfg.getStrings(YarnConfiguration.YARN_APPLICATION_CLASSPATH, YarnCompat.DEFAULT_PLATFORM_APPLICATION_CLASSPATH())) { - addToEnv(env, Environment.CLASSPATH.name(), c.trim()); - } - // add es-hadoop jar / current folder jars - addToEnv(env, Environment.CLASSPATH.name(), "./*"); - - // - // some es-yarn constants - // - addToEnv(env, EsYarnConstants.FS_URI, cfg.get(FileSystem.FS_DEFAULT_NAME_KEY, FileSystem.DEFAULT_FS)); - - return env; - } - - public static void addToEnv(Map env, String key, String value) { - String val = env.get(key); - if (val == null) { - val = value; - } - else { - val = val + YarnCompat.CLASS_PATH_SEPARATOR() + value; - } - env.put(key, val); - } - - public static void addToEnv(Map env, Map envVars) { - for (Entry entry : envVars.entrySet()) { - addToEnv(env, entry.getKey(), entry.getValue()); - } - } - - public static Object minVCores(Configuration cfg, int vCores) { - return yarnAcceptableMin(cfg, RM_SCHEDULER_MINIMUM_ALLOCATION_VCORES, DEFAULT_RM_SCHEDULER_MINIMUM_ALLOCATION_VCORES, vCores); - //return vCores; - } - - public static int minMemory(Configuration cfg, int memory) { - return yarnAcceptableMin(cfg, RM_SCHEDULER_MINIMUM_ALLOCATION_MB, DEFAULT_RM_SCHEDULER_MINIMUM_ALLOCATION_MB, memory); - //return memory; - } - - private static int yarnAcceptableMin(Configuration cfg, String property, int defaultValue, int value) { - int acceptedVal = cfg.getInt(property, defaultValue); - if (acceptedVal <= 0) { - acceptedVal = defaultValue; - } - if (acceptedVal >= value) { - return acceptedVal; - } - if (value % acceptedVal != 0) { - return acceptedVal * Math.round(value / acceptedVal); - } - return value; - } - - public static ApplicationId createAppIdFrom(String appId) { - appId = appId.substring(ApplicationId.appIdStrPrefix.length()); - int delimiter = appId.indexOf("-"); - return ApplicationId.newInstance(Long.parseLong(appId.substring(0, delimiter)), Integer.parseInt(appId.substring(delimiter + 1))); - } -} \ No newline at end of file diff --git a/yarn/src/main/resources/org/elasticsearch/hadoop/yarn/cfg/cfg.properties b/yarn/src/main/resources/org/elasticsearch/hadoop/yarn/cfg/cfg.properties deleted file mode 100644 index fd3ff92a8..000000000 --- a/yarn/src/main/resources/org/elasticsearch/hadoop/yarn/cfg/cfg.properties +++ /dev/null @@ -1,25 +0,0 @@ -# App configuration -app.name=Elasticsearch-YARN -app.tags=Elasticsearch,Long-Running,Realtime-Search -app.type=ELASTICSEARCH -app.priority=-1 -app.queue=default - -# Local Provisioning -download.local.dir=./downloads/ -download.es.url=https://download.elastic.co/elasticsearch/elasticsearch/ -es.version=${esVersionStable} - -# Provisioning -hdfs.upload.dir=/apps/elasticsearch/ -hdfs.es.yarn.jar=elasticsearch-yarn-${version}.jar - -# AM defaults -am.mem=64 -am.vcores=1 - -# Container configuration -container.priority=-1 -container.mem=2048 -container.vcores=1 -containers=1 diff --git a/yarn/src/main/resources/org/elasticsearch/hadoop/yarn/cli/help.txt b/yarn/src/main/resources/org/elasticsearch/hadoop/yarn/cli/help.txt deleted file mode 100644 index ae61d6d89..000000000 --- a/yarn/src/main/resources/org/elasticsearch/hadoop/yarn/cli/help.txt +++ /dev/null @@ -1,10 +0,0 @@ -Usage: - -download-es : Downloads Elasticsearch.zip - -install : Installs/Provisions Elasticsearch-YARN into HDFS - -install-es : Installs/Provisions Elasticsearch into HDFS - -start : Starts provisioned Elasticsearch in YARN - -status : Reports status of Elasticsearch in YARN - -stop : Stops Elasticsearch in YARN - -help : Prints this help - -Configuration options can be specified _after_ each command; see the documentation for more information. From ce5ecca0af8e7132e3929785f16cbd0d0cc8f770 Mon Sep 17 00:00:00 2001 From: James Baiera Date: Thu, 27 Jul 2017 15:59:19 -0400 Subject: [PATCH 2/3] Documentation updates for the removal of ESYarn --- docs/src/reference/asciidoc/core/intro.adoc | 2 - docs/src/reference/asciidoc/index.adoc | 18 +- .../src/reference/asciidoc/yarn/download.adoc | 47 ---- .../asciidoc/yarn/img/yarn-app-list.png | Bin 78021 -> 0 bytes .../asciidoc/yarn/img/yarn-container-list.png | Bin 63686 -> 0 bytes docs/src/reference/asciidoc/yarn/index.adoc | 27 -- .../reference/asciidoc/yarn/requirements.adoc | 69 ----- docs/src/reference/asciidoc/yarn/setup.adoc | 67 ----- docs/src/reference/asciidoc/yarn/usage.adoc | 249 ------------------ yarn/README.md | 12 +- 10 files changed, 20 insertions(+), 471 deletions(-) delete mode 100644 docs/src/reference/asciidoc/yarn/download.adoc delete mode 100644 docs/src/reference/asciidoc/yarn/img/yarn-app-list.png delete mode 100644 docs/src/reference/asciidoc/yarn/img/yarn-container-list.png delete mode 100644 docs/src/reference/asciidoc/yarn/index.adoc delete mode 100644 docs/src/reference/asciidoc/yarn/requirements.adoc delete mode 100644 docs/src/reference/asciidoc/yarn/setup.adoc delete mode 100644 docs/src/reference/asciidoc/yarn/usage.adoc diff --git a/docs/src/reference/asciidoc/core/intro.adoc b/docs/src/reference/asciidoc/core/intro.adoc index eee57345d..d09e42006 100644 --- a/docs/src/reference/asciidoc/core/intro.adoc +++ b/docs/src/reference/asciidoc/core/intro.adoc @@ -14,8 +14,6 @@ While the official name of the project is {ehtm} throughout the documentation th include::intro/typos.adoc[] TIP: If you are looking for {es} HDFS Snapshot/Restore plugin (a separate project), please refer to its https://github.com/elasticsearch/elasticsearch-hadoop/tree/master/repository-hdfs[home page]. - -TIP: If you are looking for {es} on YARN (a separate project), please refer to its dedicated <>. -- [[doc-sections]] diff --git a/docs/src/reference/asciidoc/index.adoc b/docs/src/reference/asciidoc/index.adoc index f670f2c85..368b643f7 100644 --- a/docs/src/reference/asciidoc/index.adoc +++ b/docs/src/reference/asciidoc/index.adoc @@ -27,18 +27,26 @@ {ehtm} is an `umbrella' project consisting of three similar, yet independent sub-projects with their own, dedicated, section in the documentation: -{eh} proper:: interact with {es} from within a Hadoop environment. If you are using {mr}, Hive, Pig, {sp}, {st}, or Cascading, this project is for you. For feature requests or bugs, please open an issue in the https://github.com/elastic/elasticsearch-hadoop/issues[Elasticsearch-Hadoop repository]. +{eh} proper:: +Interact with {es} from within a Hadoop environment. If you are using {mr}, Hive, Pig, {sp}, {st}, or Cascading, this +project is for you. For feature requests or bugs, please open an issue in the +https://github.com/elastic/elasticsearch-hadoop/issues[Elasticsearch-Hadoop repository]. -repository-hdfs:: use HDFS as a back-end repository for doing snapshot/restore from/to {es}. For more information, refer to its https://www.elastic.co/guide/en/elasticsearch/plugins/master/repository-hdfs.html[home page]. For feature requests or bugs, please open an issue in the https://github.com/elastic/elasticsearch/issues[Elasticsearch repository] with the ":Plugin Repository HDFS" tag. +repository-hdfs:: +Use HDFS as a back-end repository for doing snapshot/restore from/to {es}. For more information, refer to its +https://www.elastic.co/guide/en/elasticsearch/plugins/master/repository-hdfs.html[home page]. For feature requests or +bugs, please open an issue in the https://github.com/elastic/elasticsearch/issues[Elasticsearch repository] with the +":Plugin Repository HDFS" tag. -{ey}:: run {es} on top of YARN - see <>. This project is in beta. +{ey} [DISCONTINUED]:: +Run {es} on top of YARN. Due to the limitations in YARN regarding long running services, we have decided to discontinue +our development and support of the {ey} integration. If you are searching for documentation on {ey}, you can find the +documentation for the last released version https://www.elastic.co/guide/en/elasticsearch/hadoop/5.6/es-yarn.html[here]. Thus, while all projects fall under the Hadoop umbrella, each is covering a certain aspect of it so please be sure to read the appropriate documentation. For general questions around any of these projects, the https://discuss.elastic.co/c/elasticsearch-and-hadoop[Elastic Discuss forum] is a great place to interact with other users in the community. include::core/index.adoc[] -include::yarn/index.adoc[] - include::appendix/index.adoc[] diff --git a/docs/src/reference/asciidoc/yarn/download.adoc b/docs/src/reference/asciidoc/yarn/download.adoc deleted file mode 100644 index 48ae773e3..000000000 --- a/docs/src/reference/asciidoc/yarn/download.adoc +++ /dev/null @@ -1,47 +0,0 @@ -[[ey-install]] -== Installation - -{ey} binaries can be obtained either by downloading them from the http://elastic.co[elastic.co] site as a ZIP (containing project jars, sources and documentation) or by using any http://maven.apache.org/[Maven]-compatible tool with the following dependency: - -["source","xml",subs="attributes"] ----- - - org.elasticsearch - elasticsearch-yarn - {ver} - ----- - -The jar above contains {ey} and does not require any other dependencies at runtime; in other words it can be used as is. - -[[ey-download-dev]] -=== Development Builds - -Development (or nightly or snapshots) builds are published daily at 'sonatype-oss' repository (see below). Make sure to use snapshot versioning: - -["source","xml",subs="attributes"] ----- - - org.elasticsearch - elasticsearch-yarn - {ver-d} <1> - ----- - -<1> notice the 'BUILD-SNAPSHOT' suffix indicating a development build - -but also enable the dedicated snapshots repository : - -[source,xml] ----- - - - sonatype-oss - http://oss.sonatype.org/content/repositories/snapshots <1> - true <2> - - ----- - -<1> add snapshot repository -<2> enable 'snapshots' capability on the repository otherwise these will not be found by Maven \ No newline at end of file diff --git a/docs/src/reference/asciidoc/yarn/img/yarn-app-list.png b/docs/src/reference/asciidoc/yarn/img/yarn-app-list.png deleted file mode 100644 index f0a3516607805a55950e075e9b99c6c87c5458f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 78021 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 diff --git a/docs/src/reference/asciidoc/yarn/img/yarn-container-list.png b/docs/src/reference/asciidoc/yarn/img/yarn-container-list.png deleted file mode 100644 index de83da23081d5430ea893d40326a79c53d8d2ef2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63686 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

r6fpHJQ$DcocNCC&6AmI?VqTmu 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 La<1siwfp}AAIXjq diff --git a/docs/src/reference/asciidoc/yarn/index.adoc b/docs/src/reference/asciidoc/yarn/index.adoc deleted file mode 100644 index e6b6e677f..000000000 --- a/docs/src/reference/asciidoc/yarn/index.adoc +++ /dev/null @@ -1,27 +0,0 @@ -[[es-yarn]] -= Elasticsearch on YARN - -[[es-yarn-intro]] -[partintro] --- -Distributed as part of {ehtm}, {ey} is a separate, stand-alone, self-contained CLI (command-line interface) that allows {es} to run (and thus be managed) within a http://hadoop.apache.org/docs/stable/hadoop-yarn/hadoop-yarn-site/YARN.html[YARN] environment. - -In other words, {es} can use YARN to allocate its resources and be started and stopped, on said resources, through YARN infrastructure. - -IMPORTANT: -Currently, due to the inherent limitations in YARN, {ehtm} is in *beta*; that is we encourage users to try it out and report feedback however it _might_ not contain all the features needed for production usage (most of which can be addressed outside YARN). - -Unfortunately, YARN does not (currently) provide comprehensive support for long-running services; features such as storage/network/host affinity, topology information and broadcasting (in particular in case of restarts) and ip/storage provisioning are missing; while there are solutions for them, these are outside YARN which is far from ideal. - -However this topic is addressed within the YARN community - as it progresses, the new functionality will be incorporated into this project and once completed, the project will be promoted out of beta. --- - -include::requirements.adoc[] - -include::download.adoc[] - -include::setup.adoc[] - -include::usage.adoc[] - - diff --git a/docs/src/reference/asciidoc/yarn/requirements.adoc b/docs/src/reference/asciidoc/yarn/requirements.adoc deleted file mode 100644 index 76ad87979..000000000 --- a/docs/src/reference/asciidoc/yarn/requirements.adoc +++ /dev/null @@ -1,69 +0,0 @@ -[[yarn-requirements]] -== Requirements - -Before using {ey}, please pay attention to the requirements below - ignoring them can lead to abnormal behavior, error and ultimately a poor experience and data loss. - -NOTE: make sure to verify *all* nodes in a cluster when checking the version of a certain artifact. - -[[ey-requirements-yarn]] -=== YARN - -A YARN environment running on Hadoop 2.4 (or higher) is recommended. This can be easily checked by verifying the Hadoop version installed on the target nodes: - -[source,bash] ----- -$ hadoop version - -Hadoop 2.4.1 -Subversion http://svn.apache.org/repos/asf/hadoop/common -r 1604318 -Compiled by jenkins on 2014-06-21T05:43Z -Compiled with protoc 2.5.0 -From source with checksum bb7ac0a3c73dc131f4844b873c74b630 -This command was run using /opt/share/hadoop/common/hadoop-common-2.4.1.jar ----- - -For Hadoop distros, check the base core YARN/Hadoop version and make sure it is 2.4 compatible. - -As a guide, the table below lists the Hadoop-based distributions that include YARN, against with this version has been tested against at various points in time: - -|=== -| Distribution | Release - -| Apache Hadoop | 2.7.x -| Apache Hadoop | 2.6.x -| Apache Hadoop | 2.5.x -| Apache Hadoop | 2.4.x - -| Amazon EMR | 4.2.x -| Amazon EMR | 4.1.x -| Amazon EMR | 4.0.x -| Amazon EMR | 3.8.x -| Amazon EMR | 3.7.x -| Amazon EMR | 3.6.x -| Amazon EMR | 3.5.x -| Amazon EMR | 3.4.x -| Amazon EMR | 3.3.x -| Amazon EMR | 3.2.x -| Amazon EMR | 3.1.x - -| Cloudera CDH | 5.5.x -| Cloudera CDH | 5.4.x -| Cloudera CDH | 5.3.x -| Cloudera CDH | 5.2.x -| Cloudera CDH | 5.1.x -| Cloudera CDH | 5.0.x - -| Hortonworks HDP | 2.3.x -| Hortonworks HDP | 2.2.x -| Hortonworks HDP | 2.1.x - -| MapR | 5.x -| MapR | 4.1.x -| MapR | 4.0.x -|=== - - -[[ey-requirements-es]] -=== {es} - -{ey} uses the same requirements on {es} as {eh} - in other words, using the latest stable {es} is highly recommended for both stability and performance reasons. diff --git a/docs/src/reference/asciidoc/yarn/setup.adoc b/docs/src/reference/asciidoc/yarn/setup.adoc deleted file mode 100644 index 2aa5359de..000000000 --- a/docs/src/reference/asciidoc/yarn/setup.adoc +++ /dev/null @@ -1,67 +0,0 @@ -[[ey-setup]] -== Understanding the YARN environment - -[quote, Wikipedia] -____ -http://hadoop.apache.org/[YARN] stands for "Yet Another Resource Negotiator" and was added later as part of Hadoop 2.0. YARN takes the resource management capabilities that were in MapReduce and packages them so they can be used by new engines. This also streamlines MapReduce to do what it does best, process data. With YARN, you can now run multiple applications in Hadoop, all sharing a common resource management. As of September, 2014, YARN manages only CPU (number of cores) and memory [..] -____ - -In its current incarnation, {ey} interacts with the YARN APIs in order to start and stop Elasticsearch nodes on YARN infrastructure. In YARN terminology, {ey} has several components: - -Client Application:: -The entity that bootstraps the entire process and controls the life-cycle of the cluster based on user feedback. This is the CLI (Command-Line Interface) that the user interacts with. - -Application Manager:: -Based on the user configuration, the dedicated +ApplicationManager+ negotiates with YARN the number of {es} nodes to be created as YARN containers and their capabilities (memory and CPU). -It oversees the cluster life-cycle and handles the container allocation. - -Node/Container setup:: -Handles the actual {es} invocation for each allocated +Container+. - -As YARN is all about cluster resource management, it is important to properly configure YARN and {es} accordingly since over or under-allocating resources can lead to undesirable consequences. There are plenty of resources -available on how to configure and plan your YARN cluster; the section below will touch on the core components and their impact on {es}. - -=== CPU - -As of Hadoop 2.4, YARN can restrict the amount of CPU allocated to a container: each has a number of so-called +vcores+ (virtual cores) with a minimum of 1. What this translates in practice depends highly on your -underlying hardware configuration and cluster configuration; a good approximation is to map each +vcore+ to an actual core on the CPU; just like with native hardware, expect the core to be shared across the rest of the -applications so depending on system load, the amount of actual CPU available can be considerably lower. Thus, it is recommended to allocate multiple +vcores+ to {es} - a good start number being the number of actual cores -your CPU supports. - -=== Memory - -Simplifying things a lot, YARN requires containers to specify the amount of memory they need within a certain band - specifying more or less memory results in the container allocation request being denied. By default, YARN -enforces a minimum limit of 1 GB (1024 MB) and a maximum of 8 GB (8192 MB). While {es} can work with this amount of RAM, you typically want to increase this amount for performance reasons. -Out of the box, {ey} requests _only_ 2 GB of memory per container so that users can easily try it out even within a testing YARN environment (such as pseudo-distributed or VMs); significantly increase this amount once you get -beyond the YARN `Hello World' stage. - -[[ev-setup-storage]] -=== Storage - -Each container inside YARN is responsible for saving its state and storage between container restarts. In general, there are two main strategies one can take: - -Use a globally accessible file-system (like HDFS):: With a storage accessible by all Hadoop nodes, each container can use it as its backing store. For example one can use HDFS to save the data in one container and read it from another. -With {es}, one can simply mount HDFS as a https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/HdfsNfsGateway.html[NFS gateway] and simply point each {es} node to a folder on it. -Note however that performance is going to suffer significantly - HDFS is design as big, network-based storage thus each call is likely to have a significant delay (due to network latency). - -Use the container node local storage:: Each container can currently access its local storage - with proper configuration this can be kept outside the disposable container folder thus allowing the data to _live_ between restarts. -This is the recommended approach as it offers the best performance and due to {es} itself, redundancy as well (through replicas). - -Note that the approaches above require additional configuration to either {es} or your YARN cluster. There are plans to simplify this procedure in the future. - -IMPORTANT: If no storage is configured, out of the box {es} will use its container storage which means when the container is disposed, so is its data. In other words, between restarts any existing data is _destroyed_. - -=== Node affinity - -Currently, {ey} does not provide any option for tying {es} nodes to specify YARN nodes however this will be addressed in the future. In practice this means that unless YARN is specifically configured, there are no guarantees on its topology between restarts, that is on what machines {es} nodes will run each time. - -=== Security - -The Hadoop Ecosystem uses Kerberos for authentication between different components. The services that make up the -components of the Ecosystem require keytab files to be present on each node to allow for passwordless login. When -submitting an application to a secured YARN cluster, YARN runs the application as if it were the user that submitted -it. In the case of this integration, The Application Master requires access to HDFS to distribute the Elasticsearch -packages during container provisioning. The Application Master must be able to find a valid keytab file on any of the -nodes that the it may start on as well as a principal that can be found within said keytab. You can do this by using a -unique user as the owner of the Elasticsearch cluster in YARN, and distributing keytabs for this user to all machines -in the cluster. diff --git a/docs/src/reference/asciidoc/yarn/usage.adoc b/docs/src/reference/asciidoc/yarn/usage.adoc deleted file mode 100644 index 955762d2b..000000000 --- a/docs/src/reference/asciidoc/yarn/usage.adoc +++ /dev/null @@ -1,249 +0,0 @@ -[[ey-usage]] -== Usage - -{ey} allows through the command-line to provision, start, monitor and stop an {es} cluster inside a YARN environment. - -Simply download elasticsearch-yarn-.jar in a location of choice and make sure to have Hadoop/YARN available and configured in your classpath; double check through the `hadoop version` command: - -[source,bash] ----- -$ hadoop version - -Hadoop 2.4.1 -Subversion http://svn.apache.org/repos/asf/hadoop/common -r 1604318 -Compiled by jenkins on 2014-06-21T05:43Z -Compiled with protoc 2.5.0 -From source with checksum bb7ac0a3c73dc131f4844b873c74b630 -This command was run using /opt/share/hadoop/common/hadoop-common-2.4.1.jar ----- - -Once you have confirmed Hadoop is properly configured, do a basic sanity check for {ey} by invoking ++hadoop jar++: - -NOTE: Some Hadoop distros might display a warning to use ++yarn jar++ instead; the two commands can be used interchangeably - -[source,bash] ----- -$ hadoop jar elasticsearch-yarn-.jar -No command specified -Usage: - -download-es : Downloads Elasticsearch.zip - -install : Installs/Provisions Elasticsearch-YARN into HDFS - -install-es : Installs/Provisions Elasticsearch into HDFS - -start : Starts provisioned Elasticsearch in YARN - -status : Reports status of Elasticsearch in YARN - -stop : Stops Elasticsearch in YARN - -help : Prints this help - -Configuration options can be specified _after_ each command; see the documentation for more information. ----- - -Each command should be self-explanatory. The typical usage scenario is: - -[[yarn-es-download]] -[float] -=== Download the Elasticsearch version needed - -This is a _one-time_ action; if you already have {es} at hand, deploy it under +downloads+ sub-folder. To wit: - -[source,bash] ----- -$ hadoop jar elasticsearch-yarn- -download-es -Downloading Elasticsearch -Downloading ...........................................................................DONE ----- - -If you want to use a different version of {es}, you can specify so through the +es.version+ parameter (see the <> section. - -[[yarn-cfg-es]] -[float] -=== (Optional) Configuring {es} - -If the default {es} is not suitable, for example certain plugins need to be installed or the storage path needs to be defined as mentioned <>, one should do so by modifying the {es} archive as it will serve as the blueprint of _all_ nodes installed within YARN. - - -[[yarn-provision-es]] -[float] -=== Provision {es} into HDFS - -Now that we have downloaded {es}, let us upload it into HDFS so it becomes available to the Hadoop nodes. -Make sure that the proper user (typically +hdfs+) is used for writing data to HDFS; otherwise a permission denied exception will be thrown. -This is another _one-time_ action (as long as your HDFS cluster and the target location remain in place): - -[source,bash] ----- -$ hadoop jar elasticsearch-yarn-.jar -install-es - -Uploaded /opt/es-yarn/downloads/elasticsearch-.zip to HDFS at hdfs://127.0.0.1:50463/apps/elasticsearch/elasticsearch-.zip ----- - -This command uploads the `elasticsearch-.zip` (that we just downloaded) to HDFS (based on the Hadoop configuration detected in the classpath) under `/apps/elasticsearch` folder. Again the location can be <> if needed. - -Note that the uploaded ZIP can be configured accordingly to your setup - for example, one can include her own configuration (such as using a certain storage location) to override the defaults or for example certain plugins. -The zip acts as a template so be sure to include everything that need in it. - -[[yarn-provision]] -[float] -=== Provision Elasticsearch-YARN into HDFS - -Let us do the same _one-time_ command with the Elasticsearch-YARN jar: - -[source,bash] ----- -$ hadoop jar elasticsearch-yarn-.jar -install - -Uploaded opt/es-yarn/elasticsearch-yarn-.jar to HDFS at hdfs://127.0.0.1:50463/apps/elasticsearch/elasticsearch-yarn-.jar ----- - -You can verify the provisioning by interrogating HDFS either through the web console or +hadoop+ CLI: - -[source,bash] ----- -$ hadoop dfs -ls /apps/elasticsearch -Found 2 items --rw-r--r-- 1 hdfs hdfs 30901787 2014-11-13 10:17 /apps/elasticsearch/elasticsearch-.zip --rw-r--r-- 1 hdfs hdfs 52754 2014-11-13 16:16 /apps/elasticsearch/elasticsearch-yarn-.jar ----- - -[[yarn-start]] -[float] -=== Start {es} on YARN - -Once the necessary artifacts are in HDFS, one can start {es}: - -[source,bash] ----- -$ hadoop jar elasticsearch-yarn-.jar -start -Launched a 1 node Elasticsearch-YARN cluster [application_1415813090693_0001@http://hadoop:8088/proxy/application_1415921358606_0001/] at Wed Nov 14 19:24:53 EET 2014 ----- - -By default only a single node is created; to start multiple nodes use the +containers+ parameter (see <> for more information): - -[source,bash] ----- -$ hadoop jar elasticsearch-yarn-.jar -start containers=2 -Launched a 2 nodes Elasticsearch-YARN cluster [application_1415921358606_0006@http://hadoop:8088/proxy/application_1415921358606_0006/] at Wed Nov 14 19:28:46 EET 2014 ----- - -That's it! - -[[yarn-status]] -[float] -=== Get status of {es} clusters in YARN - -There are plenty of tools in Hadoop to check running YARN applications; with Elasticsearch YARN try the `-status` command: - -[source,bash] ----- -$ hadoop jar elasticsearch-yarn-.jar -status -Id State Status Start Time Finish Time Tracking URL -application_1415921358606_0007 RUNNING UNDEFINED 11/14/14 19:34 PM N/A http://hadoop:8088/proxy/application_1415921358606_0007/A ----- - -If you prefer the web ui, point your browser to the cluster console (typically on port 8088 - +http://hadoop:8088/cluster+) and the newly created {es} cluster, or rather -its +ApplicationMaster+ will show up: - -image::yarn/img/yarn-app-list.png["AppManager List",align="center"] - -One can inspect the containers manually by checking the container list (typically by accessing the +ApplicationManager+ UI): - -image::yarn/img/yarn-container-list.png["Container List",align="center"] -You should be able to see the application and the associated containers marked as +RUNNING+ ; if that is not the case, check out the logs to see what is wrong. - -[[yarn-stop]] -[float] -=== Stop {es} clusters in YARN - -To shutdown your cluster, use the +-stop+ command: - -[source,bash] ----- -$ hadoop jar elasticsearch-yarn-.jar -stop -Stopped Elasticsearch-YARN cluster with id application_1415921358606_0007 ----- - -[[yarn-options]] -[float] -=== Configuration - -{ey} offers various knobs for tweaking its behavior - all can be passed as options after each command, overriding the default configuration. Multiple options can be specified (if you specify the same parameter multiple times, the last one wins): - -[source,bash] ----- -$ hadoop jar elasticsearch-yarn-.jar [-command] [option.name]=[option.value] [option.name]=[option.value] ----- - -The following parameter are available: - -+download.local.dir+ (default ./downloads/):: -Local folder where {ey} downloads remote artifacts (like +{es}.zip+) - -+hdfs.upload.dir+ (default /apps/elasticsearch/):: -HDFS folder used for provisioning - -+es.version+ (default {es-v}):: -{es} version used for downloading, provisioning HDFS and running on the YARN cluster - -+containers+ (default 1):: -The number of containers or {es} nodes for starting the cluster - -+container.mem+ (default 2048):: -Memory requested for _each_ YARN container - -+container.vcores+ (default 1):: -CPU cores requested for _each_ YARN container - -+container.priority+ (default -1):: -YARN queue priority for each container - -+env.+:: -Pattern for setting up environment variables on each container - each property starting with +env.+ prefix will be set remotely on _each_ container: -[source,bash] ----- -$ hadoop jar elasticsearch-yarn-.jar [-command] env.ES_USE_GC_LOGGING=true env.PROP=someValue ----- -Sets up on each container two variables +ES_USE_GC_LOGGING+ and +PROP+. - -added[2.2] -+sys.prop.+:: -Pattern for setting up the JVM system property on each container - each property starting with +sys.prop.+ prefix will be set remotely on _each_ container: -[source,bash] ----- -$ hadoop jar elasticsearch-yarn-.jar [-command] sys.prop.java.security.debug="access,failure" ----- -Sets up on each JVM https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/envvars003.html[security debugging] - not something one wants in a production environment. - - -+loadConfig+:: -Property file to be loaded as configuration. That is, instead of specifying the options in each command, save them to a file and use that instead. -For example the above example, the two options (for setting the container environment variables) can be moved into a properties file -[source,init] ----- -# extra-cfg.properties -env.ES_USE_GC_LOGGING=true -env.PROP=someValue ----- -and tell {ey} to load it: -[source,bash] ----- -$ hadoop jar elasticsearch-yarn-.jar [-command] loadConfig=extra-cfg.properties ----- - -added[5.0] -+am.kerberos.principal+:: -Name of the kerberos prinicpal that the Application Master should use when connecting to HDFS to retrieve parcels for provisioning containers. -This defaults to the current system user name. When YARN is in secure container mode, the Application Master is executed using the user name -that submitted the application originally, and thus, that original user name will be used if nothing is specified for this config. -If a user specifies a +_HOST+ pattern in the principal, then the pattern will be replaced with the environment's hostname. This allows -administrators to provision a different keytab file per host. To wit: -[source,bash] ----- -elasticsearch@SECURITY.REALM <1> -elasticsearch/_HOST@SECURITY.REALM <2> ----- -<1> This principal would be unmodified no matter which host the Application Master starts on. -<2> If the Application Manager starts on a node called +pd-yarn-01+ then this principal would be modified into +elasticsearch/pd-yarn-01@SECURITY.REALM+. - -+am.kerberos.keytab+:: -Path to a readable keytab file that is accessible on every node that the Application Master may start on. The keytab -must contain valid credentials for the principal configured using the +am.kerberos.principal+ setting, either in the -format of +user@REALM+ or +user/host@REALM+. diff --git a/yarn/README.md b/yarn/README.md index 786bc99ff..fd43e348e 100644 --- a/yarn/README.md +++ b/yarn/README.md @@ -1,8 +1,10 @@ -# Elasticsearch YARN +# Elasticsearch on YARN -## :warning: Elasticsearch YARN has been removed +## :warning: Elasticsearch on YARN has been discontinued -The Elasticsearch YARN beta has been removed as of ES-Hadoop 6.0.0. For more information about the removal, please see +Due to the limitations in YARN regarding long running services, we have decided to discontinue our development and +support of the _Elasticsearch on YARN_ beta as of ES-Hadoop 6.0.0. For more information about the removal, please see the [deprecation notice on Github](https://github.com/elastic/elasticsearch-hadoop/issues/1000), or join the [discussion -topic](https://discuss.elastic.co/t/deprecation-notice-old-mr-apis-and-es-yarn/92860/3) on our forums. - +topic](https://discuss.elastic.co/t/deprecation-notice-old-mr-apis-and-es-yarn/92860/3) on our forums. If you are +searching for _Elasticsearch on YARN_ documentation, you can find the documentation for the last released version +[here](https://www.elastic.co/guide/en/elasticsearch/hadoop/5.6/es-yarn.html). From e5aa979f1188047724ceef742302029cb564354f Mon Sep 17 00:00:00 2001 From: James Baiera Date: Thu, 27 Jul 2017 16:01:18 -0400 Subject: [PATCH 3/3] clarify that the project was a beta. --- docs/src/reference/asciidoc/index.adoc | 2 +- yarn/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/reference/asciidoc/index.adoc b/docs/src/reference/asciidoc/index.adoc index 368b643f7..af059fa78 100644 --- a/docs/src/reference/asciidoc/index.adoc +++ b/docs/src/reference/asciidoc/index.adoc @@ -41,7 +41,7 @@ bugs, please open an issue in the https://github.com/elastic/elasticsearch/issue {ey} [DISCONTINUED]:: Run {es} on top of YARN. Due to the limitations in YARN regarding long running services, we have decided to discontinue our development and support of the {ey} integration. If you are searching for documentation on {ey}, you can find the -documentation for the last released version https://www.elastic.co/guide/en/elasticsearch/hadoop/5.6/es-yarn.html[here]. +documentation for the last released beta version https://www.elastic.co/guide/en/elasticsearch/hadoop/5.6/es-yarn.html[here]. Thus, while all projects fall under the Hadoop umbrella, each is covering a certain aspect of it so please be sure to read the appropriate documentation. For general questions around any of these projects, the https://discuss.elastic.co/c/elasticsearch-and-hadoop[Elastic Discuss forum] is a great place to interact with other users in the community. diff --git a/yarn/README.md b/yarn/README.md index fd43e348e..c55952ae4 100644 --- a/yarn/README.md +++ b/yarn/README.md @@ -6,5 +6,5 @@ Due to the limitations in YARN regarding long running services, we have decided support of the _Elasticsearch on YARN_ beta as of ES-Hadoop 6.0.0. For more information about the removal, please see the [deprecation notice on Github](https://github.com/elastic/elasticsearch-hadoop/issues/1000), or join the [discussion topic](https://discuss.elastic.co/t/deprecation-notice-old-mr-apis-and-es-yarn/92860/3) on our forums. If you are -searching for _Elasticsearch on YARN_ documentation, you can find the documentation for the last released version +searching for _Elasticsearch on YARN_ documentation, you can find the documentation for the last released beta version [here](https://www.elastic.co/guide/en/elasticsearch/hadoop/5.6/es-yarn.html).