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
This commit is contained in:
parent
dce1d20383
commit
8a9ae9e3ec
@ -577,6 +577,9 @@ Release 2.4.0 - UNRELEASED
|
|||||||
YARN-1866. Fixed an issue with renewal of RM-delegation tokens on restart or
|
YARN-1866. Fixed an issue with renewal of RM-delegation tokens on restart or
|
||||||
fail-over. (Jian He via vinodkv)
|
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
|
Release 2.3.1 - UNRELEASED
|
||||||
|
|
||||||
INCOMPATIBLE CHANGES
|
INCOMPATIBLE CHANGES
|
||||||
|
@ -81,6 +81,7 @@ public class RMContextImpl implements RMContext {
|
|||||||
private ApplicationMasterService applicationMasterService;
|
private ApplicationMasterService applicationMasterService;
|
||||||
private RMApplicationHistoryWriter rmApplicationHistoryWriter;
|
private RMApplicationHistoryWriter rmApplicationHistoryWriter;
|
||||||
private ConfigurationProvider configurationProvider;
|
private ConfigurationProvider configurationProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor. To be used in conjunction with setter methods for
|
* Default constructor. To be used in conjunction with setter methods for
|
||||||
* individual fields.
|
* individual fields.
|
||||||
|
@ -141,19 +141,14 @@ public class ResourceManager extends CompositeService implements Recoverable {
|
|||||||
protected ResourceScheduler scheduler;
|
protected ResourceScheduler scheduler;
|
||||||
private ClientRMService clientRM;
|
private ClientRMService clientRM;
|
||||||
protected ApplicationMasterService masterService;
|
protected ApplicationMasterService masterService;
|
||||||
private ApplicationMasterLauncher applicationMasterLauncher;
|
|
||||||
private ContainerAllocationExpirer containerAllocationExpirer;
|
|
||||||
protected NMLivelinessMonitor nmLivelinessMonitor;
|
protected NMLivelinessMonitor nmLivelinessMonitor;
|
||||||
protected NodesListManager nodesListManager;
|
protected NodesListManager nodesListManager;
|
||||||
private EventHandler<SchedulerEvent> schedulerDispatcher;
|
|
||||||
protected RMAppManager rmAppManager;
|
protected RMAppManager rmAppManager;
|
||||||
protected ApplicationACLsManager applicationACLsManager;
|
protected ApplicationACLsManager applicationACLsManager;
|
||||||
protected QueueACLsManager queueACLsManager;
|
protected QueueACLsManager queueACLsManager;
|
||||||
private DelegationTokenRenewer delegationTokenRenewer;
|
|
||||||
private WebApp webApp;
|
private WebApp webApp;
|
||||||
private AppReportFetcher fetcher = null;
|
private AppReportFetcher fetcher = null;
|
||||||
protected ResourceTrackerService resourceTracker;
|
protected ResourceTrackerService resourceTracker;
|
||||||
private boolean recoveryEnabled;
|
|
||||||
|
|
||||||
private String webAppAddress;
|
private String webAppAddress;
|
||||||
private ConfigurationProvider configurationProvider = null;
|
private ConfigurationProvider configurationProvider = null;
|
||||||
@ -333,6 +328,14 @@ protected static void validateConfigs(Configuration conf) {
|
|||||||
*/
|
*/
|
||||||
@Private
|
@Private
|
||||||
class RMActiveServices extends CompositeService {
|
class RMActiveServices extends CompositeService {
|
||||||
|
|
||||||
|
private DelegationTokenRenewer delegationTokenRenewer;
|
||||||
|
private EventHandler<SchedulerEvent> schedulerDispatcher;
|
||||||
|
private ApplicationMasterLauncher applicationMasterLauncher;
|
||||||
|
private ContainerAllocationExpirer containerAllocationExpirer;
|
||||||
|
|
||||||
|
private boolean recoveryEnabled;
|
||||||
|
|
||||||
RMActiveServices() {
|
RMActiveServices() {
|
||||||
super("RMActiveServices");
|
super("RMActiveServices");
|
||||||
}
|
}
|
||||||
@ -1009,6 +1012,11 @@ public QueueACLsManager getQueueACLsManager() {
|
|||||||
return this.queueACLsManager;
|
return this.queueACLsManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Private
|
||||||
|
WebApp getWebapp() {
|
||||||
|
return this.webApp;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void recover(RMState state) throws Exception {
|
public void recover(RMState state) throws Exception {
|
||||||
// recover RMdelegationTokenSecretManager
|
// recover RMdelegationTokenSecretManager
|
||||||
@ -1055,16 +1063,14 @@ private void resetDispatcher() {
|
|||||||
rmContext.setDispatcher(rmDispatcher);
|
rmContext.setDispatcher(rmDispatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve RM bind address from configuration
|
* Retrieve RM bind address from configuration
|
||||||
*
|
*
|
||||||
* @param conf
|
* @param conf
|
||||||
* @return InetSocketAddress
|
* @return InetSocketAddress
|
||||||
*/
|
*/
|
||||||
public static InetSocketAddress getBindAddress(Configuration conf) {
|
public static InetSocketAddress getBindAddress(Configuration conf) {
|
||||||
return conf.getSocketAddr(YarnConfiguration.RM_ADDRESS,
|
return conf.getSocketAddr(YarnConfiguration.RM_ADDRESS,
|
||||||
YarnConfiguration.DEFAULT_RM_ADDRESS,
|
YarnConfiguration.DEFAULT_RM_ADDRESS, YarnConfiguration.DEFAULT_RM_PORT);
|
||||||
YarnConfiguration.DEFAULT_RM_PORT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,19 +101,12 @@ public class RMWebServices {
|
|||||||
private final ResourceManager rm;
|
private final ResourceManager rm;
|
||||||
private static RecordFactory recordFactory = RecordFactoryProvider
|
private static RecordFactory recordFactory = RecordFactoryProvider
|
||||||
.getRecordFactory(null);
|
.getRecordFactory(null);
|
||||||
private final ApplicationACLsManager aclsManager;
|
|
||||||
private final QueueACLsManager queueACLsManager;
|
|
||||||
private final Configuration conf;
|
private final Configuration conf;
|
||||||
private @Context HttpServletResponse response;
|
private @Context HttpServletResponse response;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public RMWebServices(final ResourceManager rm,
|
public RMWebServices(final ResourceManager rm, Configuration conf) {
|
||||||
final ApplicationACLsManager aclsManager,
|
|
||||||
final QueueACLsManager queueACLsManager,
|
|
||||||
Configuration conf) {
|
|
||||||
this.rm = rm;
|
this.rm = rm;
|
||||||
this.aclsManager = aclsManager;
|
|
||||||
this.queueACLsManager = queueACLsManager;
|
|
||||||
this.conf = conf;
|
this.conf = conf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,10 +118,11 @@ protected Boolean hasAccess(RMApp app, HttpServletRequest hsr) {
|
|||||||
callerUGI = UserGroupInformation.createRemoteUser(remoteUser);
|
callerUGI = UserGroupInformation.createRemoteUser(remoteUser);
|
||||||
}
|
}
|
||||||
if (callerUGI != null
|
if (callerUGI != null
|
||||||
&& !(this.aclsManager.checkAccess(callerUGI,
|
&& !(this.rm.getApplicationACLsManager().checkAccess(callerUGI,
|
||||||
ApplicationAccessType.VIEW_APP, app.getUser(),
|
ApplicationAccessType.VIEW_APP, app.getUser(),
|
||||||
app.getApplicationId()) || this.queueACLsManager.checkAccess(
|
app.getApplicationId()) ||
|
||||||
callerUGI, QueueACL.ADMINISTER_QUEUE, app.getQueue()))) {
|
this.rm.getQueueACLsManager().checkAccess(callerUGI,
|
||||||
|
QueueACL.ADMINISTER_QUEUE, app.getQueue()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -80,6 +80,8 @@
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public class MockRM extends ResourceManager {
|
public class MockRM extends ResourceManager {
|
||||||
|
|
||||||
|
static final String ENABLE_WEBAPP = "mockrm.webapp.enabled";
|
||||||
|
|
||||||
public MockRM() {
|
public MockRM() {
|
||||||
this(new YarnConfiguration());
|
this(new YarnConfiguration());
|
||||||
}
|
}
|
||||||
@ -494,7 +496,12 @@ public RMAppManager getRMAppManager() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void startWepApp() {
|
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,
|
public static void finishAMAndVerifyAppState(RMApp rmApp, MockRM rm, MockNM nm,
|
||||||
|
@ -18,6 +18,18 @@
|
|||||||
|
|
||||||
package org.apache.hadoop.yarn.server.resourcemanager;
|
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.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
@ -25,10 +37,11 @@
|
|||||||
import org.apache.hadoop.ha.HAServiceProtocol.HAServiceState;
|
import org.apache.hadoop.ha.HAServiceProtocol.HAServiceState;
|
||||||
import org.apache.hadoop.ha.HAServiceProtocol.StateChangeRequestInfo;
|
import org.apache.hadoop.ha.HAServiceProtocol.StateChangeRequestInfo;
|
||||||
import org.apache.hadoop.ha.HealthCheckFailedException;
|
import org.apache.hadoop.ha.HealthCheckFailedException;
|
||||||
|
import org.apache.hadoop.net.NetUtils;
|
||||||
import org.apache.hadoop.security.AccessControlException;
|
import org.apache.hadoop.security.AccessControlException;
|
||||||
import org.apache.hadoop.service.AbstractService;
|
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.HAUtil;
|
||||||
|
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
||||||
import org.apache.hadoop.yarn.event.Dispatcher;
|
import org.apache.hadoop.yarn.event.Dispatcher;
|
||||||
import org.apache.hadoop.yarn.event.EventHandler;
|
import org.apache.hadoop.yarn.event.EventHandler;
|
||||||
import org.apache.hadoop.yarn.exceptions.YarnRuntimeException;
|
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.RMAppAttempt;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptState;
|
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptState;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.QueueMetrics;
|
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.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import com.sun.jersey.api.client.Client;
|
||||||
|
import com.sun.jersey.api.client.ClientResponse;
|
||||||
import org.junit.Assert;
|
import com.sun.jersey.api.client.WebResource;
|
||||||
|
import com.sun.jersey.api.client.config.DefaultClientConfig;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
public class TestRMHA {
|
public class TestRMHA {
|
||||||
private Log LOG = LogFactory.getLog(TestRMHA.class);
|
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, RM2_NODE_ID), RM2_ADDRESS);
|
||||||
configuration.set(HAUtil.addSuffix(confKey, RM3_NODE_ID), RM3_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 {
|
private void checkMonitorHealth() throws IOException {
|
||||||
@ -97,7 +112,7 @@ private void checkStandbyRMFunctionality() throws IOException {
|
|||||||
rm.adminService.getServiceStatus().isReadyToBecomeActive());
|
rm.adminService.getServiceStatus().isReadyToBecomeActive());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkActiveRMFunctionality() throws IOException {
|
private void checkActiveRMFunctionality() throws Exception {
|
||||||
assertEquals(STATE_ERR, HAServiceState.ACTIVE,
|
assertEquals(STATE_ERR, HAServiceState.ACTIVE,
|
||||||
rm.adminService.getServiceStatus().getState());
|
rm.adminService.getServiceStatus().getState());
|
||||||
assertTrue("Active RM services aren't started",
|
assertTrue("Active RM services aren't started",
|
||||||
@ -115,6 +130,33 @@ private void checkActiveRMFunctionality() throws IOException {
|
|||||||
fail("Unable to perform Active RM functions");
|
fail("Unable to perform Active RM functions");
|
||||||
LOG.error("ActiveRM check failed", e);
|
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
|
* become Active
|
||||||
*/
|
*/
|
||||||
@Test (timeout = 30000)
|
@Test (timeout = 30000)
|
||||||
public void testStartAndTransitions() throws Exception {
|
public void testFailoverAndTransitions() throws Exception {
|
||||||
configuration.setBoolean(YarnConfiguration.AUTO_FAILOVER_ENABLED, false);
|
configuration.setBoolean(YarnConfiguration.AUTO_FAILOVER_ENABLED, false);
|
||||||
Configuration conf = new YarnConfiguration(configuration);
|
Configuration conf = new YarnConfiguration(configuration);
|
||||||
|
|
||||||
rm = new MockRM(conf);
|
rm = new MockRM(conf);
|
||||||
rm.init(conf);
|
rm.init(conf);
|
||||||
StateChangeRequestInfo requestInfo = new StateChangeRequestInfo(
|
StateChangeRequestInfo requestInfo = new StateChangeRequestInfo(
|
||||||
@ -191,7 +234,7 @@ public void testStartAndTransitions() throws Exception {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransitionsWhenAutomaticFailoverEnabled() throws IOException {
|
public void testTransitionsWhenAutomaticFailoverEnabled() throws Exception {
|
||||||
final String ERR_UNFORCED_REQUEST = "User request succeeded even when " +
|
final String ERR_UNFORCED_REQUEST = "User request succeeded even when " +
|
||||||
"automatic failover is enabled";
|
"automatic failover is enabled";
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user