package org.apache.hadoop.yarn.webapp.log; import static org.apache.hadoop.yarn.webapp.YarnWebParams.APP_OWNER; import static org.apache.hadoop.yarn.webapp.YarnWebParams.CONTAINER_ID; import static org.apache.hadoop.yarn.webapp.YarnWebParams.ENTITY_STRING; import static org.apache.hadoop.yarn.webapp.YarnWebParams.NM_NODENAME; import java.io.DataInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Map; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.yarn.api.records.ApplicationAccessType; import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.api.records.ContainerId; import org.apache.hadoop.yarn.api.records.NodeId; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat; import org.apache.hadoop.yarn.logaggregation.AggregatedLogFormat.LogKey; import org.apache.hadoop.yarn.logaggregation.LogAggregationUtils; import org.apache.hadoop.yarn.server.security.ApplicationACLsManager; import org.apache.hadoop.yarn.util.ConverterUtils; import org.apache.hadoop.yarn.webapp.view.HtmlBlock; import com.google.inject.Inject; public class AggregatedLogsBlock extends HtmlBlock { private final Configuration conf; @Inject AggregatedLogsBlock(Configuration conf) { this.conf = conf; } @Override protected void render(Block html) { ContainerId containerId = verifyAndGetContainerId(html); NodeId nodeId = verifyAndGetNodeId(html); String appOwner = verifyAndGetAppOwner(html); if (containerId == null || nodeId == null || appOwner == null || appOwner.isEmpty()) { return; } ApplicationId applicationId = containerId.getApplicationAttemptId().getApplicationId(); String logEntity = $(ENTITY_STRING); if (logEntity == null || logEntity.isEmpty()) { logEntity = containerId.toString(); } if (!conf.getBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, YarnConfiguration.DEFAULT_LOG_AGGREGATION_ENABLED)) { html.h1() ._("Aggregation is not enabled. Try the nodemanager at " + nodeId) ._(); return; } Path remoteRootLogDir = new Path(conf.get(YarnConfiguration.NM_REMOTE_APP_LOG_DIR, YarnConfiguration.DEFAULT_NM_REMOTE_APP_LOG_DIR)); AggregatedLogFormat.LogReader reader = null; try { reader = new AggregatedLogFormat.LogReader(conf, LogAggregationUtils.getRemoteNodeLogFileForApp( remoteRootLogDir, applicationId, appOwner, nodeId, LogAggregationUtils.getRemoteNodeLogDirSuffix(conf))); } catch (FileNotFoundException e) { // ACLs not available till the log file is opened. html.h1() ._("Logs not available for " + logEntity + ". Aggregation may not be complete, " + "Check back later or try the nodemanager at " + nodeId)._(); return; } catch (IOException e) { html.h1()._("Error getting logs for " + logEntity)._(); LOG.error("Error getting logs for " + logEntity, e); return; } String owner = null; Map<ApplicationAccessType, String> appAcls = null; try { owner = reader.getApplicationOwner(); appAcls = reader.getApplicationAcls(); } catch (IOException e) { html.h1()._("Error getting logs for " + logEntity)._(); LOG.error("Error getting logs for " + logEntity, e); return; } ApplicationACLsManager aclsManager = new ApplicationACLsManager(conf); aclsManager.addApplication(applicationId, appAcls); String remoteUser = request().getRemoteUser(); UserGroupInformation callerUGI = null; if (remoteUser != null) { callerUGI = UserGroupInformation.createRemoteUser(remoteUser); } if (callerUGI != null && !aclsManager.checkAccess(callerUGI, ApplicationAccessType.VIEW_APP, owner, applicationId)) { html.h1() ._("User [" + remoteUser + "] is not authorized to view the logs for " + logEntity)._(); return; } DataInputStream valueStream; LogKey key = new LogKey(); try { valueStream = reader.next(key); while (valueStream != null && !key.toString().equals(containerId.toString())) { valueStream = reader.next(key); } if (valueStream == null) { html.h1()._( "Logs not available for " + logEntity + ". Could be caused by the rentention policy")._(); return; } writer().write("<pre>"); AggregatedLogFormat.LogReader.readAcontainerLogs(valueStream, writer()); writer().write("</pre>"); return; } catch (IOException e) { html.h1()._("Error getting logs for " + logEntity)._(); LOG.error("Error getting logs for " + logEntity, e); return; } } private ContainerId verifyAndGetContainerId(Block html) { String containerIdStr = $(CONTAINER_ID); if (containerIdStr == null || containerIdStr.isEmpty()) { html.h1()._("Cannot get container logs without a ContainerId")._(); return null; } ContainerId containerId = null; try { containerId = ConverterUtils.toContainerId(containerIdStr); } catch (IllegalArgumentException e) { html.h1() ._("Cannot get container logs for invalid containerId: " + containerIdStr)._(); return null; } return containerId; } private NodeId verifyAndGetNodeId(Block html) { String nodeIdStr = $(NM_NODENAME); if (nodeIdStr == null || nodeIdStr.isEmpty()) { html.h1()._("Cannot get container logs without a NodeId")._(); return null; } NodeId nodeId = null; try { nodeId = ConverterUtils.toNodeId(nodeIdStr); } catch (IllegalArgumentException e) { html.h1()._("Cannot get container logs. Invalid nodeId: " + nodeIdStr) ._(); return null; } return nodeId; } private String verifyAndGetAppOwner(Block html) { String appOwner = $(APP_OWNER); if (appOwner == null || appOwner.isEmpty()) { html.h1()._("Cannot get container logs without an app owner")._(); } return appOwner; } }