Search in sources :

Example 1 with LogWriter

use of org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogWriter in project hadoop by apache.

the class TestAggregatedLogFormat method testContainerLogsFileAccess.

@Test(timeout = 10000)
public void testContainerLogsFileAccess() throws IOException {
    // This test will run only if NativeIO is enabled as SecureIOUtils 
    // require it to be enabled.
    Assume.assumeTrue(NativeIO.isAvailable());
    Configuration conf = new Configuration();
    conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, "kerberos");
    UserGroupInformation.setConfiguration(conf);
    File workDir = new File(testWorkDir, "testContainerLogsFileAccess1");
    Path remoteAppLogFile = new Path(workDir.getAbsolutePath(), "aggregatedLogFile");
    Path srcFileRoot = new Path(workDir.getAbsolutePath(), "srcFiles");
    String data = "Log File content for container : ";
    // Creating files for container1. Log aggregator will try to read log files
    // with illegal user.
    ApplicationId applicationId = ApplicationId.newInstance(1, 1);
    ApplicationAttemptId applicationAttemptId = ApplicationAttemptId.newInstance(applicationId, 1);
    ContainerId testContainerId1 = ContainerId.newContainerId(applicationAttemptId, 1);
    Path appDir = new Path(srcFileRoot, testContainerId1.getApplicationAttemptId().getApplicationId().toString());
    Path srcFilePath1 = new Path(appDir, testContainerId1.toString());
    String stdout = "stdout";
    String stderr = "stderr";
    writeSrcFile(srcFilePath1, stdout, data + testContainerId1.toString() + stdout);
    writeSrcFile(srcFilePath1, stderr, data + testContainerId1.toString() + stderr);
    UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
    LogWriter logWriter = new LogWriter(conf, remoteAppLogFile, ugi);
    LogKey logKey = new LogKey(testContainerId1);
    String randomUser = "randomUser";
    LogValue logValue = spy(new LogValue(Collections.singletonList(srcFileRoot.toString()), testContainerId1, randomUser));
    // It is trying simulate a situation where first log file is owned by
    // different user (probably symlink) and second one by the user itself.
    // The first file should not be aggregated. Because this log file has the invalid
    // user name.
    when(logValue.getUser()).thenReturn(randomUser).thenReturn(ugi.getShortUserName());
    logWriter.append(logKey, logValue);
    logWriter.close();
    BufferedReader in = new BufferedReader(new FileReader(new File(remoteAppLogFile.toUri().getRawPath())));
    String line;
    StringBuffer sb = new StringBuffer("");
    while ((line = in.readLine()) != null) {
        LOG.info(line);
        sb.append(line);
    }
    line = sb.toString();
    String expectedOwner = ugi.getShortUserName();
    if (Path.WINDOWS) {
        final String adminsGroupString = "Administrators";
        if (Arrays.asList(ugi.getGroupNames()).contains(adminsGroupString)) {
            expectedOwner = adminsGroupString;
        }
    }
    // This file: stderr should not be aggregated.
    // And we will not aggregate the log message.
    String stdoutFile1 = StringUtils.join(File.separator, Arrays.asList(new String[] { workDir.getAbsolutePath(), "srcFiles", testContainerId1.getApplicationAttemptId().getApplicationId().toString(), testContainerId1.toString(), stderr }));
    // The file: stdout is expected to be aggregated.
    String stdoutFile2 = StringUtils.join(File.separator, Arrays.asList(new String[] { workDir.getAbsolutePath(), "srcFiles", testContainerId1.getApplicationAttemptId().getApplicationId().toString(), testContainerId1.toString(), stdout }));
    String message2 = "Owner '" + expectedOwner + "' for path " + stdoutFile2 + " did not match expected owner '" + ugi.getShortUserName() + "'";
    Assert.assertFalse(line.contains(message2));
    Assert.assertFalse(line.contains(data + testContainerId1.toString() + stderr));
    Assert.assertTrue(line.contains(data + testContainerId1.toString() + stdout));
}
Also used : Path(org.apache.hadoop.fs.Path) Configuration(org.apache.hadoop.conf.Configuration) LogKey(org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogKey) ApplicationAttemptId(org.apache.hadoop.yarn.api.records.ApplicationAttemptId) LogValue(org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogValue) TestContainerId(org.apache.hadoop.yarn.api.TestContainerId) ContainerId(org.apache.hadoop.yarn.api.records.ContainerId) LogWriter(org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogWriter) BufferedReader(java.io.BufferedReader) FileReader(java.io.FileReader) ApplicationId(org.apache.hadoop.yarn.api.records.ApplicationId) File(java.io.File) UserGroupInformation(org.apache.hadoop.security.UserGroupInformation) Test(org.junit.Test)

Example 2 with LogWriter

use of org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogWriter in project hadoop by apache.

the class TestAggregatedLogFormat method writeSrcFileAndALog.

private void writeSrcFileAndALog(Path srcFilePath, String fileName, final long length, Path remoteAppLogFile, Path srcFileRoot, ContainerId testContainerId) throws Exception {
    File dir = new File(srcFilePath.toString());
    if (!dir.exists()) {
        if (!dir.mkdirs()) {
            throw new IOException("Unable to create directory : " + dir);
        }
    }
    File outputFile = new File(new File(srcFilePath.toString()), fileName);
    FileOutputStream os = new FileOutputStream(outputFile);
    final OutputStreamWriter osw = new OutputStreamWriter(os, "UTF8");
    final int ch = filler;
    UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
    LogWriter logWriter = new LogWriter(new Configuration(), remoteAppLogFile, ugi);
    LogKey logKey = new LogKey(testContainerId);
    LogValue logValue = spy(new LogValue(Collections.singletonList(srcFileRoot.toString()), testContainerId, ugi.getShortUserName()));
    final CountDownLatch latch = new CountDownLatch(1);
    Thread t = new Thread() {

        public void run() {
            try {
                for (int i = 0; i < length / 3; i++) {
                    osw.write(ch);
                }
                latch.countDown();
                for (int i = 0; i < (2 * length) / 3; i++) {
                    osw.write(ch);
                }
                osw.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    };
    t.start();
    //Wait till the osw is partially written
    //aggregation starts once the ows has completed 1/3rd of its work
    latch.await();
    //Aggregate The Logs
    logWriter.append(logKey, logValue);
    logWriter.close();
}
Also used : Configuration(org.apache.hadoop.conf.Configuration) LogValue(org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogValue) LogWriter(org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogWriter) FileOutputStream(java.io.FileOutputStream) LogKey(org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogKey) OutputStreamWriter(java.io.OutputStreamWriter) IOException(java.io.IOException) CountDownLatch(java.util.concurrent.CountDownLatch) File(java.io.File) UserGroupInformation(org.apache.hadoop.security.UserGroupInformation)

Example 3 with LogWriter

use of org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogWriter in project hadoop by apache.

the class TestAggregatedLogFormat method testReadAcontainerLog.

private void testReadAcontainerLog(boolean logUploadedTime) throws Exception {
    Configuration conf = new Configuration();
    File workDir = new File(testWorkDir, "testReadAcontainerLogs1");
    Path remoteAppLogFile = new Path(workDir.getAbsolutePath(), "aggregatedLogFile");
    Path srcFileRoot = new Path(workDir.getAbsolutePath(), "srcFiles");
    ContainerId testContainerId = TestContainerId.newContainerId(1, 1, 1, 1);
    Path t = new Path(srcFileRoot, testContainerId.getApplicationAttemptId().getApplicationId().toString());
    Path srcFilePath = new Path(t, testContainerId.toString());
    int numChars = 80000;
    // create a sub-folder under srcFilePath
    // and create file logs in this sub-folder.
    // We only aggregate top level files.
    // So, this log file should be ignored.
    Path subDir = new Path(srcFilePath, "subDir");
    fs.mkdirs(subDir);
    writeSrcFile(subDir, "logs", numChars);
    // create file stderr and stdout in containerLogDir
    writeSrcFile(srcFilePath, "stderr", numChars);
    writeSrcFile(srcFilePath, "stdout", numChars);
    UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
    LogWriter logWriter = new LogWriter(conf, remoteAppLogFile, ugi);
    LogKey logKey = new LogKey(testContainerId);
    LogValue logValue = new LogValue(Collections.singletonList(srcFileRoot.toString()), testContainerId, ugi.getShortUserName());
    // When we try to open FileInputStream for stderr, it will throw out an IOException.
    // Skip the log aggregation for stderr.
    LogValue spyLogValue = spy(logValue);
    File errorFile = new File((new Path(srcFilePath, "stderr")).toString());
    doThrow(new IOException("Mock can not open FileInputStream")).when(spyLogValue).secureOpenFile(errorFile);
    logWriter.append(logKey, spyLogValue);
    logWriter.close();
    // make sure permission are correct on the file
    FileStatus fsStatus = fs.getFileStatus(remoteAppLogFile);
    Assert.assertEquals("permissions on log aggregation file are wrong", FsPermission.createImmutable((short) 0640), fsStatus.getPermission());
    LogReader logReader = new LogReader(conf, remoteAppLogFile);
    LogKey rLogKey = new LogKey();
    DataInputStream dis = logReader.next(rLogKey);
    Writer writer = new StringWriter();
    if (logUploadedTime) {
        LogReader.readAcontainerLogs(dis, writer, System.currentTimeMillis());
    } else {
        LogReader.readAcontainerLogs(dis, writer);
    }
    // We should only do the log aggregation for stdout.
    // Since we could not open the fileInputStream for stderr, this file is not
    // aggregated.
    String s = writer.toString();
    int expectedLength = "LogType:stdout".length() + (logUploadedTime ? ("\nLog Upload Time:" + Times.format(System.currentTimeMillis())).length() : 0) + ("\nLogLength:" + numChars).length() + "\nLog Contents:\n".length() + numChars + "\n".length() + "\nEnd of LogType:stdout\n".length();
    Assert.assertTrue("LogType not matched", s.contains("LogType:stdout"));
    Assert.assertTrue("log file:stderr should not be aggregated.", !s.contains("LogType:stderr"));
    Assert.assertTrue("log file:logs should not be aggregated.", !s.contains("LogType:logs"));
    Assert.assertTrue("LogLength not matched", s.contains("LogLength:" + numChars));
    Assert.assertTrue("Log Contents not matched", s.contains("Log Contents"));
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < numChars; i++) {
        sb.append(filler);
    }
    String expectedContent = sb.toString();
    Assert.assertTrue("Log content incorrect", s.contains(expectedContent));
    Assert.assertEquals(expectedLength, s.length());
}
Also used : Path(org.apache.hadoop.fs.Path) FileStatus(org.apache.hadoop.fs.FileStatus) Configuration(org.apache.hadoop.conf.Configuration) LogKey(org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogKey) IOException(java.io.IOException) DataInputStream(java.io.DataInputStream) LogValue(org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogValue) StringWriter(java.io.StringWriter) TestContainerId(org.apache.hadoop.yarn.api.TestContainerId) ContainerId(org.apache.hadoop.yarn.api.records.ContainerId) LogWriter(org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogWriter) LogReader(org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogReader) File(java.io.File) LogWriter(org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogWriter) OutputStreamWriter(java.io.OutputStreamWriter) StringWriter(java.io.StringWriter) Writer(java.io.Writer) UserGroupInformation(org.apache.hadoop.security.UserGroupInformation)

Example 4 with LogWriter

use of org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogWriter in project hadoop by apache.

the class AppLogAggregatorImpl method uploadLogsForContainers.

private void uploadLogsForContainers(boolean appFinished) {
    if (this.logAggregationDisabled) {
        return;
    }
    if (UserGroupInformation.isSecurityEnabled()) {
        Credentials systemCredentials = context.getSystemCredentialsForApps().get(appId);
        if (systemCredentials != null) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Adding new framework-token for " + appId + " for log-aggregation: " + systemCredentials.getAllTokens() + "; userUgi=" + userUgi);
            }
            // this will replace old token
            userUgi.addCredentials(systemCredentials);
        }
    }
    // Create a set of Containers whose logs will be uploaded in this cycle.
    // It includes:
    // a) all containers in pendingContainers: those containers are finished
    //    and satisfy the ContainerLogAggregationPolicy.
    // b) some set of running containers: For all the Running containers,
    //    we use exitCode of 0 to find those which satisfy the
    //    ContainerLogAggregationPolicy.
    Set<ContainerId> pendingContainerInThisCycle = new HashSet<ContainerId>();
    this.pendingContainers.drainTo(pendingContainerInThisCycle);
    Set<ContainerId> finishedContainers = new HashSet<ContainerId>(pendingContainerInThisCycle);
    if (this.context.getApplications().get(this.appId) != null) {
        for (Container container : this.context.getApplications().get(this.appId).getContainers().values()) {
            ContainerType containerType = container.getContainerTokenIdentifier().getContainerType();
            if (shouldUploadLogs(new ContainerLogContext(container.getContainerId(), containerType, 0))) {
                pendingContainerInThisCycle.add(container.getContainerId());
            }
        }
    }
    LogWriter writer = null;
    String diagnosticMessage = "";
    boolean logAggregationSucceedInThisCycle = true;
    try {
        if (pendingContainerInThisCycle.isEmpty()) {
            return;
        }
        logAggregationTimes++;
        try {
            writer = createLogWriter();
            // Write ACLs once when the writer is created.
            writer.writeApplicationACLs(appAcls);
            writer.writeApplicationOwner(this.userUgi.getShortUserName());
        } catch (IOException e1) {
            logAggregationSucceedInThisCycle = false;
            LOG.error("Cannot create writer for app " + this.applicationId + ". Skip log upload this time. ", e1);
            return;
        }
        boolean uploadedLogsInThisCycle = false;
        for (ContainerId container : pendingContainerInThisCycle) {
            ContainerLogAggregator aggregator = null;
            if (containerLogAggregators.containsKey(container)) {
                aggregator = containerLogAggregators.get(container);
            } else {
                aggregator = new ContainerLogAggregator(container);
                containerLogAggregators.put(container, aggregator);
            }
            Set<Path> uploadedFilePathsInThisCycle = aggregator.doContainerLogAggregation(writer, appFinished, finishedContainers.contains(container));
            if (uploadedFilePathsInThisCycle.size() > 0) {
                uploadedLogsInThisCycle = true;
                this.delService.delete(this.userUgi.getShortUserName(), null, uploadedFilePathsInThisCycle.toArray(new Path[uploadedFilePathsInThisCycle.size()]));
            }
            // remove it from containerLogAggregators.
            if (finishedContainers.contains(container)) {
                containerLogAggregators.remove(container);
            }
        }
        // is smaller than the configured NM log aggregation retention size.
        if (uploadedLogsInThisCycle && logAggregationInRolling) {
            cleanOldLogs();
            cleanupOldLogTimes++;
        }
        if (writer != null) {
            writer.close();
            writer = null;
        }
        long currentTime = System.currentTimeMillis();
        final Path renamedPath = this.rollingMonitorInterval <= 0 ? remoteNodeLogFileForApp : new Path(remoteNodeLogFileForApp.getParent(), remoteNodeLogFileForApp.getName() + "_" + currentTime);
        final boolean rename = uploadedLogsInThisCycle;
        try {
            userUgi.doAs(new PrivilegedExceptionAction<Object>() {

                @Override
                public Object run() throws Exception {
                    FileSystem remoteFS = remoteNodeLogFileForApp.getFileSystem(conf);
                    if (rename) {
                        remoteFS.rename(remoteNodeTmpLogFileForApp, renamedPath);
                    } else {
                        remoteFS.delete(remoteNodeTmpLogFileForApp, false);
                    }
                    return null;
                }
            });
            diagnosticMessage = "Log uploaded successfully for Application: " + appId + " in NodeManager: " + LogAggregationUtils.getNodeString(nodeId) + " at " + Times.format(currentTime) + "\n";
        } catch (Exception e) {
            LOG.error("Failed to move temporary log file to final location: [" + remoteNodeTmpLogFileForApp + "] to [" + renamedPath + "]", e);
            diagnosticMessage = "Log uploaded failed for Application: " + appId + " in NodeManager: " + LogAggregationUtils.getNodeString(nodeId) + " at " + Times.format(currentTime) + "\n";
            renameTemporaryLogFileFailed = true;
            logAggregationSucceedInThisCycle = false;
        }
    } finally {
        LogAggregationStatus logAggregationStatus = logAggregationSucceedInThisCycle ? LogAggregationStatus.RUNNING : LogAggregationStatus.RUNNING_WITH_FAILURE;
        sendLogAggregationReport(logAggregationStatus, diagnosticMessage);
        if (appFinished) {
            // If the app is finished, one extra final report with log aggregation
            // status SUCCEEDED/FAILED will be sent to RM to inform the RM
            // that the log aggregation in this NM is completed.
            LogAggregationStatus finalLogAggregationStatus = renameTemporaryLogFileFailed || !logAggregationSucceedInThisCycle ? LogAggregationStatus.FAILED : LogAggregationStatus.SUCCEEDED;
            sendLogAggregationReport(finalLogAggregationStatus, "");
        }
        if (writer != null) {
            writer.close();
        }
    }
}
Also used : Path(org.apache.hadoop.fs.Path) ContainerType(org.apache.hadoop.yarn.server.api.ContainerType) ContainerLogContext(org.apache.hadoop.yarn.server.api.ContainerLogContext) IOException(java.io.IOException) IOException(java.io.IOException) UnsupportedFileSystemException(org.apache.hadoop.fs.UnsupportedFileSystemException) Container(org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container) ContainerId(org.apache.hadoop.yarn.api.records.ContainerId) LogWriter(org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogWriter) FileSystem(org.apache.hadoop.fs.FileSystem) LogAggregationStatus(org.apache.hadoop.yarn.api.records.LogAggregationStatus) Credentials(org.apache.hadoop.security.Credentials) HashSet(java.util.HashSet)

Aggregations

LogWriter (org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogWriter)4 File (java.io.File)3 IOException (java.io.IOException)3 Configuration (org.apache.hadoop.conf.Configuration)3 Path (org.apache.hadoop.fs.Path)3 UserGroupInformation (org.apache.hadoop.security.UserGroupInformation)3 ContainerId (org.apache.hadoop.yarn.api.records.ContainerId)3 LogKey (org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogKey)3 LogValue (org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogValue)3 OutputStreamWriter (java.io.OutputStreamWriter)2 TestContainerId (org.apache.hadoop.yarn.api.TestContainerId)2 BufferedReader (java.io.BufferedReader)1 DataInputStream (java.io.DataInputStream)1 FileOutputStream (java.io.FileOutputStream)1 FileReader (java.io.FileReader)1 StringWriter (java.io.StringWriter)1 Writer (java.io.Writer)1 HashSet (java.util.HashSet)1 CountDownLatch (java.util.concurrent.CountDownLatch)1 FileStatus (org.apache.hadoop.fs.FileStatus)1