YARN-3517. RM web ui for dumping scheduler logs should be for admins only (Varun Vasudev via tgraves)
(cherry picked from commit 2e215484bd
)
This commit is contained in:
parent
460127e6f2
commit
2e13183f60
|
@ -220,6 +220,9 @@ Release 2.8.0 - UNRELEASED
|
|||
YARN-2740. Fix NodeLabelsManager to properly handle node label modifications
|
||||
when distributed node label configuration enabled. (Naganarasimha G R via wangda)
|
||||
|
||||
YARN-3517. RM web ui for dumping scheduler logs should be for admins only
|
||||
(Varun Vasudev via tgraves)
|
||||
|
||||
Release 2.7.1 - UNRELEASED
|
||||
|
||||
INCOMPATIBLE CHANGES
|
||||
|
|
|
@ -138,4 +138,15 @@ public class ApplicationACLsManager {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given user in an admin.
|
||||
*
|
||||
* @param calledUGI
|
||||
* UserGroupInformation for the user
|
||||
* @return true if the user is an admin, false otherwise
|
||||
*/
|
||||
public final boolean isAdmin(final UserGroupInformation calledUGI) {
|
||||
return this.adminAclsManager.isAdmin(calledUGI);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.hadoop.util.StringUtils;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerHealth;
|
||||
|
@ -33,6 +34,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.UserInfo
|
|||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.CapacitySchedulerInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.CapacitySchedulerLeafQueueInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.CapacitySchedulerQueueInfo;
|
||||
import org.apache.hadoop.yarn.server.security.ApplicationACLsManager;
|
||||
import org.apache.hadoop.yarn.util.Times;
|
||||
import org.apache.hadoop.yarn.webapp.ResponseInfo;
|
||||
import org.apache.hadoop.yarn.webapp.SubView;
|
||||
|
@ -190,28 +192,46 @@ class CapacitySchedulerPage extends RmView {
|
|||
static class QueuesBlock extends HtmlBlock {
|
||||
final CapacityScheduler cs;
|
||||
final CSQInfo csqinfo;
|
||||
private final ResourceManager rm;
|
||||
|
||||
@Inject QueuesBlock(ResourceManager rm, CSQInfo info) {
|
||||
cs = (CapacityScheduler) rm.getResourceScheduler();
|
||||
csqinfo = info;
|
||||
this.rm = rm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Block html) {
|
||||
html._(MetricsOverviewTable.class);
|
||||
// Dump CapacityScheduler debug logs
|
||||
|
||||
UserGroupInformation callerUGI = this.getCallerUGI();
|
||||
boolean isAdmin = false;
|
||||
ApplicationACLsManager aclsManager = rm.getApplicationACLsManager();
|
||||
if (aclsManager.areACLsEnabled()) {
|
||||
if (callerUGI != null && aclsManager.isAdmin(callerUGI)) {
|
||||
isAdmin = true;
|
||||
}
|
||||
} else {
|
||||
isAdmin = true;
|
||||
}
|
||||
|
||||
// only show button to dump CapacityScheduler debug logs to admins
|
||||
if (isAdmin) {
|
||||
html.div()
|
||||
.button()
|
||||
.$onclick("confirmAction()").b("Dump scheduler logs")._()
|
||||
.select().$id("time")
|
||||
.option().$value("60")._("1 min")._()
|
||||
.option().$value("300")._("5 min")._()
|
||||
.option().$value("600")._("10 min")._()
|
||||
.$style(
|
||||
"border-style: solid; border-color: #000000; border-width: 1px;"
|
||||
+ " cursor: hand; cursor: pointer; border-radius: 4px")
|
||||
.$onclick("confirmAction()").b("Dump scheduler logs")._().select()
|
||||
.$id("time").option().$value("60")._("1 min")._().option()
|
||||
.$value("300")._("5 min")._().option().$value("600")._("10 min")._()
|
||||
._()._();
|
||||
|
||||
StringBuilder script = new StringBuilder();
|
||||
script.append("function confirmAction() {")
|
||||
.append(" b = confirm(\"Are you sure you wish to generate scheduler logs?\");")
|
||||
script
|
||||
.append("function confirmAction() {")
|
||||
.append(" b = confirm(\"Are you sure you wish to generate"
|
||||
+ " scheduler logs?\");")
|
||||
.append(" if (b == true) {")
|
||||
.append(" var timePeriod = $(\"#time\").val();")
|
||||
.append(" $.ajax({")
|
||||
|
@ -225,13 +245,14 @@ class CapacitySchedulerPage extends RmView {
|
|||
.append(" alert(\"Scheduler log is being generated.\");")
|
||||
.append(" }, 1000);")
|
||||
.append(" }).fail(function(data){")
|
||||
.append(" alert(\"Scheduler log generation failed. Please check the ResourceManager log for more informtion.\");")
|
||||
.append(" console.log(data);")
|
||||
.append(" });")
|
||||
.append(" }")
|
||||
.append(
|
||||
" alert(\"Scheduler log generation failed. Please check the"
|
||||
+ " ResourceManager log for more informtion.\");")
|
||||
.append(" console.log(data);").append(" });").append(" }")
|
||||
.append("}");
|
||||
|
||||
html.script().$type("text/javascript")._(script.toString())._();
|
||||
}
|
||||
|
||||
UL<DIV<DIV<Hamlet>>> ul = html.
|
||||
div("#cs-wrapper.ui-widget").
|
||||
|
|
|
@ -142,10 +142,12 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ResourceInfo;
|
|||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerTypeInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.StatisticsItemInfo;
|
||||
import org.apache.hadoop.yarn.server.security.ApplicationACLsManager;
|
||||
import org.apache.hadoop.yarn.server.utils.BuilderUtils;
|
||||
import org.apache.hadoop.yarn.util.AdHocLogDumper;
|
||||
import org.apache.hadoop.yarn.util.ConverterUtils;
|
||||
import org.apache.hadoop.yarn.webapp.BadRequestException;
|
||||
import org.apache.hadoop.yarn.webapp.ForbiddenException;
|
||||
import org.apache.hadoop.yarn.webapp.NotFoundException;
|
||||
import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
|
||||
|
||||
|
@ -263,8 +265,17 @@ public class RMWebServices {
|
|||
@POST
|
||||
@Path("/scheduler/logs")
|
||||
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
public String dumpSchedulerLogs(@FormParam("time") String time) throws IOException {
|
||||
public String dumpSchedulerLogs(@FormParam("time") String time,
|
||||
@Context HttpServletRequest hsr) throws IOException {
|
||||
init();
|
||||
UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
|
||||
ApplicationACLsManager aclsManager = rm.getApplicationACLsManager();
|
||||
if (aclsManager.areACLsEnabled()) {
|
||||
if (callerUGI == null || !aclsManager.isAdmin(callerUGI)) {
|
||||
String msg = "Only admins can carry out this operation.";
|
||||
throw new ForbiddenException(msg);
|
||||
}
|
||||
}
|
||||
ResourceScheduler rs = rm.getResourceScheduler();
|
||||
int period = Integer.parseInt(time);
|
||||
if (period <= 0) {
|
||||
|
|
|
@ -26,7 +26,9 @@ import static org.mockito.Matchers.isA;
|
|||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.StringReader;
|
||||
import java.security.Principal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
@ -37,6 +39,7 @@ import javax.ws.rs.core.MediaType;
|
|||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.service.Service.STATE;
|
||||
import org.apache.hadoop.util.VersionInfo;
|
||||
|
@ -54,9 +57,13 @@ import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager;
|
|||
import org.apache.hadoop.yarn.server.resourcemanager.nodelabels.RMNodeLabelsManager;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.QueueMetrics;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fifo.FifoScheduler;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppsInfo;
|
||||
import org.apache.hadoop.yarn.server.security.ApplicationACLsManager;
|
||||
import org.apache.hadoop.yarn.util.YarnVersionInfo;
|
||||
import org.apache.hadoop.yarn.webapp.ForbiddenException;
|
||||
import org.apache.hadoop.yarn.webapp.GenericExceptionHandler;
|
||||
import org.apache.hadoop.yarn.webapp.JerseyTestBase;
|
||||
import org.apache.hadoop.yarn.webapp.WebServicesTestUtils;
|
||||
|
@ -643,4 +650,74 @@ public class TestRMWebServices extends JerseyTestBase {
|
|||
null, null, null, null, null, null, null, emptySet, emptySet);
|
||||
assertTrue(appsInfo.getApps().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDumpingSchedulerLogs() throws Exception {
|
||||
|
||||
ResourceManager mockRM = mock(ResourceManager.class);
|
||||
Configuration conf = new YarnConfiguration();
|
||||
HttpServletRequest mockHsr = mock(HttpServletRequest.class);
|
||||
ApplicationACLsManager aclsManager = new ApplicationACLsManager(conf);
|
||||
when(mockRM.getApplicationACLsManager()).thenReturn(aclsManager);
|
||||
RMWebServices webSvc =
|
||||
new RMWebServices(mockRM, conf, mock(HttpServletResponse.class));
|
||||
|
||||
// nothing should happen
|
||||
webSvc.dumpSchedulerLogs("1", mockHsr);
|
||||
Thread.sleep(1000);
|
||||
checkSchedulerLogFileAndCleanup();
|
||||
|
||||
conf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
|
||||
conf.setStrings(YarnConfiguration.YARN_ADMIN_ACL, "admin");
|
||||
aclsManager = new ApplicationACLsManager(conf);
|
||||
when(mockRM.getApplicationACLsManager()).thenReturn(aclsManager);
|
||||
webSvc = new RMWebServices(mockRM, conf, mock(HttpServletResponse.class));
|
||||
boolean exceptionThrown = false;
|
||||
try {
|
||||
webSvc.dumpSchedulerLogs("1", mockHsr);
|
||||
fail("Dumping logs should fail");
|
||||
} catch (ForbiddenException ae) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
assertTrue("ForbiddenException expected", exceptionThrown);
|
||||
exceptionThrown = false;
|
||||
when(mockHsr.getUserPrincipal()).thenReturn(new Principal() {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "testuser";
|
||||
}
|
||||
});
|
||||
try {
|
||||
webSvc.dumpSchedulerLogs("1", mockHsr);
|
||||
fail("Dumping logs should fail");
|
||||
} catch (ForbiddenException ae) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
assertTrue("ForbiddenException expected", exceptionThrown);
|
||||
|
||||
when(mockHsr.getUserPrincipal()).thenReturn(new Principal() {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "admin";
|
||||
}
|
||||
});
|
||||
webSvc.dumpSchedulerLogs("1", mockHsr);
|
||||
Thread.sleep(1000);
|
||||
checkSchedulerLogFileAndCleanup();
|
||||
}
|
||||
|
||||
private void checkSchedulerLogFileAndCleanup() {
|
||||
String targetFile;
|
||||
ResourceScheduler scheduler = rm.getResourceScheduler();
|
||||
if (scheduler instanceof FairScheduler) {
|
||||
targetFile = "yarn-fair-scheduler-debug.log";
|
||||
} else if (scheduler instanceof CapacityScheduler) {
|
||||
targetFile = "yarn-capacity-scheduler-debug.log";
|
||||
} else {
|
||||
targetFile = "yarn-scheduler-debug.log";
|
||||
}
|
||||
File logFile = new File(System.getProperty("yarn.log.dir"), targetFile);
|
||||
assertTrue("scheduler log file doesn't exist", logFile.exists());
|
||||
FileUtils.deleteQuietly(logFile);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue