From 8a9ae9e3ecb6946838e54bb0c3b8282c3215d8ab Mon Sep 17 00:00:00 2001 From: Vinod Kumar Vavilapalli Date: Wed, 26 Mar 2014 03:03:17 +0000 Subject: [PATCH] YARN-1867. Fixed a bug in ResourceManager that was causing invalid ACL checks in the web-services after fail-over. Contributed by Vinod Kumar Vavilapalli. git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1581662 13f79535-47bb-0310-9956-ffa450edef68 --- hadoop-yarn-project/CHANGES.txt | 3 + .../server/resourcemanager/RMContextImpl.java | 1 + .../resourcemanager/ResourceManager.java | 26 ++++--- .../resourcemanager/webapp/RMWebServices.java | 18 ++--- .../yarn/server/resourcemanager/MockRM.java | 9 ++- .../yarn/server/resourcemanager/TestRMHA.java | 67 +++++++++++++++---- 6 files changed, 89 insertions(+), 35 deletions(-) diff --git a/hadoop-yarn-project/CHANGES.txt b/hadoop-yarn-project/CHANGES.txt index ce686c4d5b..4476aff90f 100644 --- a/hadoop-yarn-project/CHANGES.txt +++ b/hadoop-yarn-project/CHANGES.txt @@ -577,6 +577,9 @@ Release 2.4.0 - UNRELEASED YARN-1866. Fixed an issue with renewal of RM-delegation tokens on restart or fail-over. (Jian He via vinodkv) + YARN-1867. Fixed a bug in ResourceManager that was causing invalid ACL checks + in the web-services after fail-over. (Vinod Kumar Vavilapalli) + Release 2.3.1 - UNRELEASED INCOMPATIBLE CHANGES diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMContextImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMContextImpl.java index 689a091419..1eb4b752fa 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMContextImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMContextImpl.java @@ -81,6 +81,7 @@ public class RMContextImpl implements RMContext { private ApplicationMasterService applicationMasterService; private RMApplicationHistoryWriter rmApplicationHistoryWriter; private ConfigurationProvider configurationProvider; + /** * Default constructor. To be used in conjunction with setter methods for * individual fields. diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceManager.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceManager.java index df3d800616..054ec042da 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceManager.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceManager.java @@ -141,19 +141,14 @@ public class ResourceManager extends CompositeService implements Recoverable { protected ResourceScheduler scheduler; private ClientRMService clientRM; protected ApplicationMasterService masterService; - private ApplicationMasterLauncher applicationMasterLauncher; - private ContainerAllocationExpirer containerAllocationExpirer; protected NMLivelinessMonitor nmLivelinessMonitor; protected NodesListManager nodesListManager; - private EventHandler schedulerDispatcher; protected RMAppManager rmAppManager; protected ApplicationACLsManager applicationACLsManager; protected QueueACLsManager queueACLsManager; - private DelegationTokenRenewer delegationTokenRenewer; private WebApp webApp; private AppReportFetcher fetcher = null; protected ResourceTrackerService resourceTracker; - private boolean recoveryEnabled; private String webAppAddress; private ConfigurationProvider configurationProvider = null; @@ -333,6 +328,14 @@ protected static void validateConfigs(Configuration conf) { */ @Private class RMActiveServices extends CompositeService { + + private DelegationTokenRenewer delegationTokenRenewer; + private EventHandler schedulerDispatcher; + private ApplicationMasterLauncher applicationMasterLauncher; + private ContainerAllocationExpirer containerAllocationExpirer; + + private boolean recoveryEnabled; + RMActiveServices() { super("RMActiveServices"); } @@ -1009,6 +1012,11 @@ public QueueACLsManager getQueueACLsManager() { return this.queueACLsManager; } + @Private + WebApp getWebapp() { + return this.webApp; + } + @Override public void recover(RMState state) throws Exception { // recover RMdelegationTokenSecretManager @@ -1055,16 +1063,14 @@ private void resetDispatcher() { rmContext.setDispatcher(rmDispatcher); } - /** * Retrieve RM bind address from configuration - * + * * @param conf * @return InetSocketAddress */ -public static InetSocketAddress getBindAddress(Configuration conf) { + public static InetSocketAddress getBindAddress(Configuration conf) { return conf.getSocketAddr(YarnConfiguration.RM_ADDRESS, - YarnConfiguration.DEFAULT_RM_ADDRESS, - YarnConfiguration.DEFAULT_RM_PORT); + YarnConfiguration.DEFAULT_RM_ADDRESS, YarnConfiguration.DEFAULT_RM_PORT); } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java index 60fbfcdebe..56eba34620 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java @@ -101,19 +101,12 @@ public class RMWebServices { private final ResourceManager rm; private static RecordFactory recordFactory = RecordFactoryProvider .getRecordFactory(null); - private final ApplicationACLsManager aclsManager; - private final QueueACLsManager queueACLsManager; private final Configuration conf; private @Context HttpServletResponse response; @Inject - public RMWebServices(final ResourceManager rm, - final ApplicationACLsManager aclsManager, - final QueueACLsManager queueACLsManager, - Configuration conf) { + public RMWebServices(final ResourceManager rm, Configuration conf) { this.rm = rm; - this.aclsManager = aclsManager; - this.queueACLsManager = queueACLsManager; this.conf = conf; } @@ -125,10 +118,11 @@ protected Boolean hasAccess(RMApp app, HttpServletRequest hsr) { callerUGI = UserGroupInformation.createRemoteUser(remoteUser); } if (callerUGI != null - && !(this.aclsManager.checkAccess(callerUGI, - ApplicationAccessType.VIEW_APP, app.getUser(), - app.getApplicationId()) || this.queueACLsManager.checkAccess( - callerUGI, QueueACL.ADMINISTER_QUEUE, app.getQueue()))) { + && !(this.rm.getApplicationACLsManager().checkAccess(callerUGI, + ApplicationAccessType.VIEW_APP, app.getUser(), + app.getApplicationId()) || + this.rm.getQueueACLsManager().checkAccess(callerUGI, + QueueACL.ADMINISTER_QUEUE, app.getQueue()))) { return false; } return true; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockRM.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockRM.java index 596e309f5d..caee228f87 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockRM.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/MockRM.java @@ -80,6 +80,8 @@ @SuppressWarnings("unchecked") public class MockRM extends ResourceManager { + static final String ENABLE_WEBAPP = "mockrm.webapp.enabled"; + public MockRM() { this(new YarnConfiguration()); } @@ -494,7 +496,12 @@ public RMAppManager getRMAppManager() { @Override protected void startWepApp() { - // override to disable webapp + if (getConfig().getBoolean(ENABLE_WEBAPP, false)) { + super.startWepApp(); + return; + } + + // Disable webapp } public static void finishAMAndVerifyAppState(RMApp rmApp, MockRM rm, MockNM nm, diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestRMHA.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestRMHA.java index a01d488340..5252f5620c 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestRMHA.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestRMHA.java @@ -18,6 +18,18 @@ package org.apache.hadoop.yarn.server.resourcemanager; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.net.InetSocketAddress; + +import javax.ws.rs.core.MediaType; + +import junit.framework.Assert; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; @@ -25,10 +37,11 @@ import org.apache.hadoop.ha.HAServiceProtocol.HAServiceState; import org.apache.hadoop.ha.HAServiceProtocol.StateChangeRequestInfo; import org.apache.hadoop.ha.HealthCheckFailedException; +import org.apache.hadoop.net.NetUtils; import org.apache.hadoop.security.AccessControlException; import org.apache.hadoop.service.AbstractService; -import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.conf.HAUtil; +import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.event.Dispatcher; import org.apache.hadoop.yarn.event.EventHandler; import org.apache.hadoop.yarn.exceptions.YarnRuntimeException; @@ -36,17 +49,15 @@ import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptState; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.QueueMetrics; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; import org.junit.Before; import org.junit.Test; -import java.io.IOException; - -import org.junit.Assert; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.api.client.config.DefaultClientConfig; public class TestRMHA { private Log LOG = LogFactory.getLog(TestRMHA.class); @@ -77,6 +88,10 @@ public void setUp() throws Exception { configuration.set(HAUtil.addSuffix(confKey, RM2_NODE_ID), RM2_ADDRESS); configuration.set(HAUtil.addSuffix(confKey, RM3_NODE_ID), RM3_ADDRESS); } + + // Enable webapp to test web-services also + configuration.setBoolean(MockRM.ENABLE_WEBAPP, true); + configuration.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true); } private void checkMonitorHealth() throws IOException { @@ -97,7 +112,7 @@ private void checkStandbyRMFunctionality() throws IOException { rm.adminService.getServiceStatus().isReadyToBecomeActive()); } - private void checkActiveRMFunctionality() throws IOException { + private void checkActiveRMFunctionality() throws Exception { assertEquals(STATE_ERR, HAServiceState.ACTIVE, rm.adminService.getServiceStatus().getState()); assertTrue("Active RM services aren't started", @@ -115,6 +130,33 @@ private void checkActiveRMFunctionality() throws IOException { fail("Unable to perform Active RM functions"); LOG.error("ActiveRM check failed", e); } + + checkActiveRMWebServices(); + } + + // Do some sanity testing of the web-services after fail-over. + private void checkActiveRMWebServices() throws JSONException { + + // Validate web-service + Client webServiceClient = Client.create(new DefaultClientConfig()); + InetSocketAddress rmWebappAddr = + NetUtils.getConnectAddress(rm.getWebapp().getListenerAddress()); + String webappURL = + "http://" + rmWebappAddr.getHostName() + ":" + rmWebappAddr.getPort(); + WebResource webResource = webServiceClient.resource(webappURL); + String path = app.getApplicationId().toString(); + + ClientResponse response = + webResource.path("ws").path("v1").path("cluster").path("apps") + .path(path).accept(MediaType.APPLICATION_JSON) + .get(ClientResponse.class); + assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); + JSONObject json = response.getEntity(JSONObject.class); + + assertEquals("incorrect number of elements", 1, json.length()); + JSONObject appJson = json.getJSONObject("app"); + assertEquals("ACCEPTED", appJson.getString("state")); + // Other stuff is verified in the regular web-services related tests } /** @@ -129,9 +171,10 @@ private void checkActiveRMFunctionality() throws IOException { * become Active */ @Test (timeout = 30000) - public void testStartAndTransitions() throws Exception { + public void testFailoverAndTransitions() throws Exception { configuration.setBoolean(YarnConfiguration.AUTO_FAILOVER_ENABLED, false); Configuration conf = new YarnConfiguration(configuration); + rm = new MockRM(conf); rm.init(conf); StateChangeRequestInfo requestInfo = new StateChangeRequestInfo( @@ -191,7 +234,7 @@ public void testStartAndTransitions() throws Exception { } @Test - public void testTransitionsWhenAutomaticFailoverEnabled() throws IOException { + public void testTransitionsWhenAutomaticFailoverEnabled() throws Exception { final String ERR_UNFORCED_REQUEST = "User request succeeded even when " + "automatic failover is enabled";