/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.yarn.logaggregation; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileWriter; import java.io.PrintWriter; import java.io.Writer; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileUtil; 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.ApplicationAttemptId; import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.api.records.ContainerId; import org.apache.hadoop.yarn.api.records.impl.pb.ApplicationAttemptIdPBImpl; import org.apache.hadoop.yarn.api.records.impl.pb.ApplicationIdPBImpl; import org.apache.hadoop.yarn.api.records.impl.pb.ContainerIdPBImpl; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.webapp.YarnWebParams; import org.apache.hadoop.yarn.webapp.log.AggregatedLogsBlockForTest; import org.apache.hadoop.yarn.webapp.view.BlockForTest; import org.apache.hadoop.yarn.webapp.view.HtmlBlock; import org.apache.hadoop.yarn.webapp.view.HtmlBlockForTest; import org.junit.Test; import static org.mockito.Mockito.*; import static org.junit.Assert.*; /** * Test AggregatedLogsBlock. AggregatedLogsBlock should check user, aggregate a * logs into one file and show this logs or errors into html code * */ public class TestAggregatedLogsBlock { /** * Bad user. User 'owner' is trying to read logs without access */ @Test public void testAccessDenied() throws Exception { FileUtil.fullyDelete(new File("target/logs")); Configuration configuration = getConfiguration(); writeLogs("target/logs/logs/application_0_0001/container_0_0001_01_000001"); writeLog(configuration, "owner"); AggregatedLogsBlockForTest aggregatedBlock = getAggregatedLogsBlockForTest( configuration, "owner", "container_0_0001_01_000001"); ByteArrayOutputStream data = new ByteArrayOutputStream(); PrintWriter printWriter = new PrintWriter(data); HtmlBlock html = new HtmlBlockForTest(); HtmlBlock.Block block = new BlockForTest(html, printWriter, 10, false); aggregatedBlock.render(block); block.getWriter().flush(); String out = data.toString(); assertTrue(out .contains("User [owner] is not authorized to view the logs for entity")); } /** * try to read bad logs * * @throws Exception */ @Test public void testBadLogs() throws Exception { FileUtil.fullyDelete(new File("target/logs")); Configuration configuration = getConfiguration(); writeLogs("target/logs/logs/application_0_0001/container_0_0001_01_000001"); writeLog(configuration, "owner"); AggregatedLogsBlockForTest aggregatedBlock = getAggregatedLogsBlockForTest( configuration, "admin", "container_0_0001_01_000001"); ByteArrayOutputStream data = new ByteArrayOutputStream(); PrintWriter printWriter = new PrintWriter(data); HtmlBlock html = new HtmlBlockForTest(); HtmlBlock.Block block = new BlockForTest(html, printWriter, 10, false); aggregatedBlock.render(block); block.getWriter().flush(); String out = data.toString(); assertTrue(out .contains("Logs not available for entity. Aggregation may not be complete, Check back later or try the nodemanager at localhost:1234")); } /** * All ok and the AggregatedLogsBlockFor should aggregate logs and show it. * * @throws Exception */ @Test public void testAggregatedLogsBlock() throws Exception { FileUtil.fullyDelete(new File("target/logs")); Configuration configuration = getConfiguration(); writeLogs("target/logs/logs/application_0_0001/container_0_0001_01_000001"); writeLog(configuration, "admin"); AggregatedLogsBlockForTest aggregatedBlock = getAggregatedLogsBlockForTest( configuration, "admin", "container_0_0001_01_000001"); ByteArrayOutputStream data = new ByteArrayOutputStream(); PrintWriter printWriter = new PrintWriter(data); HtmlBlock html = new HtmlBlockForTest(); HtmlBlock.Block block = new BlockForTest(html, printWriter, 10, false); aggregatedBlock.render(block); block.getWriter().flush(); String out = data.toString(); assertTrue(out.contains("test log1")); assertTrue(out.contains("test log2")); assertTrue(out.contains("test log3")); } /** * Log files was deleted. * * @throws Exception */ @Test public void testNoLogs() throws Exception { FileUtil.fullyDelete(new File("target/logs")); Configuration configuration = getConfiguration(); File f = new File("target/logs/logs/application_0_0001/container_0_0001_01_000001"); if (!f.exists()) { assertTrue(f.mkdirs()); } writeLog(configuration, "admin"); AggregatedLogsBlockForTest aggregatedBlock = getAggregatedLogsBlockForTest( configuration, "admin", "container_0_0001_01_000001"); ByteArrayOutputStream data = new ByteArrayOutputStream(); PrintWriter printWriter = new PrintWriter(data); HtmlBlock html = new HtmlBlockForTest(); HtmlBlock.Block block = new BlockForTest(html, printWriter, 10, false); aggregatedBlock.render(block); block.getWriter().flush(); String out = data.toString(); assertTrue(out.contains("No logs available for container container_0_0001_01_000001")); } private Configuration getConfiguration() { Configuration configuration = new Configuration(); configuration.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true); configuration.set(YarnConfiguration.NM_REMOTE_APP_LOG_DIR, "target/logs"); configuration.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true); configuration.set(YarnConfiguration.YARN_ADMIN_ACL, "admin"); return configuration; } private AggregatedLogsBlockForTest getAggregatedLogsBlockForTest( Configuration configuration, String user, String containerId) { HttpServletRequest request = mock(HttpServletRequest.class); when(request.getRemoteUser()).thenReturn(user); AggregatedLogsBlockForTest aggregatedBlock = new AggregatedLogsBlockForTest( configuration); aggregatedBlock.setRequest(request); aggregatedBlock.moreParams().put(YarnWebParams.CONTAINER_ID, containerId); aggregatedBlock.moreParams().put(YarnWebParams.NM_NODENAME, "localhost:1234"); aggregatedBlock.moreParams().put(YarnWebParams.APP_OWNER, user); aggregatedBlock.moreParams().put("start", ""); aggregatedBlock.moreParams().put("end", ""); aggregatedBlock.moreParams().put(YarnWebParams.ENTITY_STRING, "entity"); return aggregatedBlock; } private void writeLog(Configuration configuration, String user) throws Exception { ApplicationId appId = ApplicationIdPBImpl.newInstance(0, 1); ApplicationAttemptId appAttemptId = ApplicationAttemptIdPBImpl.newInstance(appId, 1); ContainerId containerId = ContainerIdPBImpl.newInstance(appAttemptId, 1); String path = "target/logs/" + user + "/logs/application_0_0001/localhost_1234"; File f = new File(path); if (!f.getParentFile().exists()) { assertTrue(f.getParentFile().mkdirs()); } List<String> rootLogDirs = Arrays.asList("target/logs/logs"); UserGroupInformation ugi = UserGroupInformation.getCurrentUser(); AggregatedLogFormat.LogWriter writer = new AggregatedLogFormat.LogWriter( configuration, new Path(path), ugi); writer.writeApplicationOwner(ugi.getUserName()); Map<ApplicationAccessType, String> appAcls = new HashMap<ApplicationAccessType, String>(); appAcls.put(ApplicationAccessType.VIEW_APP, ugi.getUserName()); writer.writeApplicationACLs(appAcls); writer.append(new AggregatedLogFormat.LogKey("container_0_0001_01_000001"), new AggregatedLogFormat.LogValue(rootLogDirs, containerId,UserGroupInformation.getCurrentUser().getShortUserName())); writer.close(); } private void writeLogs(String dirName) throws Exception { File f = new File(dirName + File.separator + "log1"); if (!f.getParentFile().exists()) { assertTrue(f.getParentFile().mkdirs()); } writeLog(dirName + File.separator + "log1", "test log1"); writeLog(dirName + File.separator + "log2", "test log2"); writeLog(dirName + File.separator + "log3", "test log3"); } private void writeLog(String fileName, String text) throws Exception { File f = new File(fileName); Writer writer = new FileWriter(f); writer.write(text); writer.flush(); writer.close(); } }