|
@@ -20,10 +20,14 @@ package org.apache.hadoop.yarn.service.client;
|
|
|
|
|
|
import com.google.common.annotations.VisibleForTesting;
|
|
|
|
|
|
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
|
|
|
+import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
|
|
|
+import org.apache.commons.compress.utils.IOUtils;
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
import org.apache.curator.framework.CuratorFramework;
|
|
|
import org.apache.curator.framework.CuratorFrameworkFactory;
|
|
|
import org.apache.curator.retry.RetryNTimes;
|
|
|
+import org.apache.curator.shaded.com.google.common.io.Files;
|
|
|
import org.apache.hadoop.classification.InterfaceAudience;
|
|
|
import org.apache.hadoop.classification.InterfaceStability;
|
|
|
import org.apache.hadoop.conf.Configuration;
|
|
@@ -73,6 +77,8 @@ import org.apache.hadoop.yarn.service.api.records.ComponentContainers;
|
|
|
import org.apache.hadoop.yarn.service.api.records.Container;
|
|
|
import org.apache.hadoop.yarn.service.api.records.ContainerState;
|
|
|
import org.apache.hadoop.yarn.service.api.records.Component;
|
|
|
+import org.apache.hadoop.yarn.service.api.records.ConfigFile;
|
|
|
+import org.apache.hadoop.yarn.service.api.records.ConfigFile.TypeEnum;
|
|
|
import org.apache.hadoop.yarn.service.api.records.Service;
|
|
|
import org.apache.hadoop.yarn.service.api.records.ServiceState;
|
|
|
import org.apache.hadoop.yarn.service.conf.SliderExitCodes;
|
|
@@ -97,12 +103,18 @@ import org.apache.hadoop.yarn.util.Times;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
+import java.io.BufferedOutputStream;
|
|
|
import java.io.File;
|
|
|
+import java.io.FileInputStream;
|
|
|
+import java.io.FileOutputStream;
|
|
|
import java.io.IOException;
|
|
|
+import java.io.OutputStreamWriter;
|
|
|
+import java.io.Writer;
|
|
|
import java.net.InetSocketAddress;
|
|
|
import java.net.URI;
|
|
|
import java.net.URISyntaxException;
|
|
|
import java.nio.ByteBuffer;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
import java.text.MessageFormat;
|
|
|
import java.util.*;
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
@@ -929,6 +941,8 @@ public class ServiceClient extends AppAdminClient implements SliderExitCodes,
|
|
|
addJarResource(serviceName, localResources);
|
|
|
// add keytab if in secure env
|
|
|
addKeytabResourceIfSecure(fs, localResources, app);
|
|
|
+ // add yarn sysfs to localResources
|
|
|
+ addYarnSysFs(appRootDir, localResources, app);
|
|
|
if (LOG.isDebugEnabled()) {
|
|
|
printLocalResources(localResources);
|
|
|
}
|
|
@@ -938,8 +952,8 @@ public class ServiceClient extends AppAdminClient implements SliderExitCodes,
|
|
|
String cmdStr = buildCommandLine(app, conf, appRootDir, hasAMLog4j);
|
|
|
submissionContext.setResource(Resource.newInstance(YarnServiceConf
|
|
|
.getLong(YarnServiceConf.AM_RESOURCE_MEM,
|
|
|
- YarnServiceConf.DEFAULT_KEY_AM_RESOURCE_MEM, app.getConfiguration(),
|
|
|
- conf), 1));
|
|
|
+ YarnServiceConf.DEFAULT_KEY_AM_RESOURCE_MEM,
|
|
|
+ app.getConfiguration(), conf), 1));
|
|
|
String queue = app.getQueue();
|
|
|
if (StringUtils.isEmpty(queue)) {
|
|
|
queue = conf.get(YARN_QUEUE, DEFAULT_YARN_QUEUE);
|
|
@@ -963,6 +977,128 @@ public class ServiceClient extends AppAdminClient implements SliderExitCodes,
|
|
|
return submissionContext.getApplicationId();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Compress (tar) the input files to the output file.
|
|
|
+ *
|
|
|
+ * @param files The files to compress
|
|
|
+ * @param output The resulting output file (should end in .tar.gz)
|
|
|
+ * @param bundleRoot
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ public static File compressFiles(Collection<File> files, File output,
|
|
|
+ String bundleRoot) throws IOException {
|
|
|
+ try (FileOutputStream fos = new FileOutputStream(output);
|
|
|
+ TarArchiveOutputStream taos = new TarArchiveOutputStream(
|
|
|
+ new BufferedOutputStream(fos))) {
|
|
|
+ taos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
|
|
|
+ for (File f : files) {
|
|
|
+ addFilesToCompression(taos, f, "sysfs", bundleRoot);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return output;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Compile file list for compression and going recursive for
|
|
|
+ * nested directories.
|
|
|
+ *
|
|
|
+ * @param taos The archive
|
|
|
+ * @param file The file to add to the archive
|
|
|
+ * @param dir The directory that should serve as
|
|
|
+ * the parent directory in the archive
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ private static void addFilesToCompression(TarArchiveOutputStream taos,
|
|
|
+ File file, String dir, String bundleRoot) throws IOException {
|
|
|
+ if (!file.isHidden()) {
|
|
|
+ // Create an entry for the file
|
|
|
+ if (!dir.equals(".")) {
|
|
|
+ if (File.separator.equals("\\")) {
|
|
|
+ dir = dir.replaceAll("\\\\", "/");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ taos.putArchiveEntry(
|
|
|
+ new TarArchiveEntry(file, dir + "/" + file.getName()));
|
|
|
+ if (file.isFile()) {
|
|
|
+ // Add the file to the archive
|
|
|
+ try (FileInputStream input = new FileInputStream(file)) {
|
|
|
+ IOUtils.copy(input, taos);
|
|
|
+ taos.closeArchiveEntry();
|
|
|
+ }
|
|
|
+ } else if (file.isDirectory()) {
|
|
|
+ // close the archive entry
|
|
|
+ if (!dir.equals(".")) {
|
|
|
+ taos.closeArchiveEntry();
|
|
|
+ }
|
|
|
+ // go through all the files in the directory and using recursion, add
|
|
|
+ // them to the archive
|
|
|
+ File[] allFiles = file.listFiles();
|
|
|
+ if (allFiles != null) {
|
|
|
+ for (File childFile : allFiles) {
|
|
|
+ addFilesToCompression(taos, childFile,
|
|
|
+ file.getPath().substring(bundleRoot.length()), bundleRoot);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addYarnSysFs(Path path,
|
|
|
+ Map<String, LocalResource> localResources, Service app)
|
|
|
+ throws IOException {
|
|
|
+ List<Component> componentsWithYarnSysFS = new ArrayList<Component>();
|
|
|
+ for(Component c : app.getComponents()) {
|
|
|
+ boolean enabled = Boolean.parseBoolean(c.getConfiguration()
|
|
|
+ .getEnv(ApplicationConstants.Environment
|
|
|
+ .YARN_CONTAINER_RUNTIME_YARN_SYSFS_ENABLE.name()));
|
|
|
+ if (enabled) {
|
|
|
+ componentsWithYarnSysFS.add(c);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(componentsWithYarnSysFS.size() == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String buffer = ServiceApiUtil.jsonSerDeser.toJson(app);
|
|
|
+ File tmpDir = Files.createTempDir();
|
|
|
+ if (tmpDir.exists()) {
|
|
|
+ String serviceJsonPath = tmpDir.getAbsolutePath() + "/app.json";
|
|
|
+ File localFile = new File(serviceJsonPath);
|
|
|
+ if (localFile.createNewFile()) {
|
|
|
+ try (Writer writer = new OutputStreamWriter(
|
|
|
+ new FileOutputStream(localFile), StandardCharsets.UTF_8)) {
|
|
|
+ writer.write(buffer);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ throw new IOException("Fail to write app.json to temp directory");
|
|
|
+ }
|
|
|
+ File destinationFile = new File(tmpDir.getAbsolutePath() + "/sysfs.tar");
|
|
|
+ if (!destinationFile.createNewFile()) {
|
|
|
+ throw new IOException("Fail to localize sysfs.tar.");
|
|
|
+ }
|
|
|
+ List<File> files = new ArrayList<File>();
|
|
|
+ files.add(localFile);
|
|
|
+ compressFiles(files, destinationFile, "sysfs");
|
|
|
+ LocalResource localResource =
|
|
|
+ fs.submitFile(destinationFile, path, ".", "sysfs.tar");
|
|
|
+ Path serviceJson = new Path(path, "sysfs.tar");
|
|
|
+ for (Component c : componentsWithYarnSysFS) {
|
|
|
+ ConfigFile e = new ConfigFile();
|
|
|
+ e.type(TypeEnum.ARCHIVE);
|
|
|
+ e.srcFile(serviceJson.toString());
|
|
|
+ e.destFile("/hadoop/yarn");
|
|
|
+ if (!c.getConfiguration().getFiles().contains(e)) {
|
|
|
+ c.getConfiguration().getFiles().add(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ localResources.put("sysfs", localResource);
|
|
|
+ if (!tmpDir.delete()) {
|
|
|
+ LOG.warn("Failed to delete temp file: " + tmpDir.getAbsolutePath());
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ throw new IOException("Fail to localize sysfs resource.");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private void setLogAggregationContext(Service app, Configuration conf,
|
|
|
ApplicationSubmissionContext submissionContext) {
|
|
|
LogAggregationContext context = Records.newRecord(LogAggregationContext
|
|
@@ -1565,4 +1701,5 @@ public class ServiceClient extends AppAdminClient implements SliderExitCodes,
|
|
|
this.principalName = principalName;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
}
|