YARN-11315. [Federation] YARN Federation Router Supports Cross-Origin. (#4934)
This commit is contained in:
parent
2122733c30
commit
82a88a8ae6
|
@ -4194,6 +4194,11 @@ public class YarnConfiguration extends Configuration {
|
||||||
ROUTER_WEBAPP_PREFIX + "appsinfo-cached-count";
|
ROUTER_WEBAPP_PREFIX + "appsinfo-cached-count";
|
||||||
public static final int DEFAULT_ROUTER_APPSINFO_CACHED_COUNT = 100;
|
public static final int DEFAULT_ROUTER_APPSINFO_CACHED_COUNT = 100;
|
||||||
|
|
||||||
|
/** Enable cross origin (CORS) support. **/
|
||||||
|
public static final String ROUTER_WEBAPP_ENABLE_CORS_FILTER =
|
||||||
|
ROUTER_PREFIX + "webapp.cross-origin.enabled";
|
||||||
|
public static final boolean DEFAULT_ROUTER_WEBAPP_ENABLE_CORS_FILTER = false;
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// CSI Volume configs
|
// CSI Volume configs
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
|
@ -28,6 +28,7 @@ import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.classification.VisibleForTesting;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.http.HttpServer2;
|
import org.apache.hadoop.http.HttpServer2;
|
||||||
import org.apache.hadoop.util.Lists;
|
import org.apache.hadoop.util.Lists;
|
||||||
|
@ -299,4 +300,8 @@ public abstract class WebApp extends ServletModule {
|
||||||
|
|
||||||
public abstract void setup();
|
public abstract void setup();
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public HttpServer2 getHttpServer() {
|
||||||
|
return httpServer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5006,7 +5006,18 @@
|
||||||
Default is 100
|
Default is 100
|
||||||
</description>
|
</description>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
|
<property>
|
||||||
|
<name>yarn.router.webapp.cross-origin.enabled</name>
|
||||||
|
<value>false</value>
|
||||||
|
<description>
|
||||||
|
Flag to enable cross-origin (CORS) support for Yarn Router.
|
||||||
|
For Yarn Router, also add
|
||||||
|
org.apache.hadoop.security.HttpCrossOriginFilterInitializer to the
|
||||||
|
configuration hadoop.http.filter.initializers in core-site.xml.
|
||||||
|
</description>
|
||||||
|
</property>
|
||||||
|
|
||||||
<property>
|
<property>
|
||||||
<name>yarn.federation.state-store.max-applications</name>
|
<name>yarn.federation.state-store.max-applications</name>
|
||||||
<value>1000</value>
|
<value>1000</value>
|
||||||
|
|
|
@ -129,6 +129,12 @@
|
||||||
<type>test-jar</type>
|
<type>test-jar</type>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.grizzly</groupId>
|
||||||
|
<artifactId>grizzly-http-servlet</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.apache.hadoop.classification.InterfaceAudience.Private;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
|
import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
|
||||||
import org.apache.hadoop.metrics2.source.JvmMetrics;
|
import org.apache.hadoop.metrics2.source.JvmMetrics;
|
||||||
|
import org.apache.hadoop.security.HttpCrossOriginFilterInitializer;
|
||||||
import org.apache.hadoop.security.SecurityUtil;
|
import org.apache.hadoop.security.SecurityUtil;
|
||||||
import org.apache.hadoop.service.CompositeService;
|
import org.apache.hadoop.service.CompositeService;
|
||||||
import org.apache.hadoop.util.JvmPauseMonitor;
|
import org.apache.hadoop.util.JvmPauseMonitor;
|
||||||
|
@ -168,6 +169,16 @@ public class Router extends CompositeService {
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void startWepApp() {
|
public void startWepApp() {
|
||||||
|
|
||||||
|
// Initialize RouterWeb's CrossOrigin capability.
|
||||||
|
boolean enableCors = conf.getBoolean(YarnConfiguration.ROUTER_WEBAPP_ENABLE_CORS_FILTER,
|
||||||
|
YarnConfiguration.DEFAULT_ROUTER_WEBAPP_ENABLE_CORS_FILTER);
|
||||||
|
if (enableCors) {
|
||||||
|
conf.setBoolean(HttpCrossOriginFilterInitializer.PREFIX
|
||||||
|
+ HttpCrossOriginFilterInitializer.ENABLED_SUFFIX, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.info("Instantiating RouterWebApp at {}.", webAppAddress);
|
||||||
|
|
||||||
RMWebAppUtil.setupSecurityAndFilters(conf, null);
|
RMWebAppUtil.setupSecurityAndFilters(conf, null);
|
||||||
|
|
||||||
Builder<Object> builder =
|
Builder<Object> builder =
|
||||||
|
|
|
@ -22,11 +22,27 @@ import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
|
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
|
||||||
|
import org.apache.hadoop.http.HttpServer2;
|
||||||
|
import org.apache.hadoop.security.HttpCrossOriginFilterInitializer;
|
||||||
import org.apache.hadoop.security.authorize.AccessControlList;
|
import org.apache.hadoop.security.authorize.AccessControlList;
|
||||||
import org.apache.hadoop.security.authorize.ServiceAuthorizationManager;
|
import org.apache.hadoop.security.authorize.ServiceAuthorizationManager;
|
||||||
|
import org.apache.hadoop.security.http.CrossOriginFilter;
|
||||||
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
||||||
|
import org.apache.hadoop.yarn.webapp.WebApp;
|
||||||
|
import org.eclipse.jetty.servlet.FilterHolder;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHandler;
|
||||||
|
import org.eclipse.jetty.webapp.WebAppContext;
|
||||||
|
import org.glassfish.grizzly.servlet.HttpServletResponseImpl;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link Router}.
|
* Tests {@link Router}.
|
||||||
|
@ -87,4 +103,97 @@ public class TestRouter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRouterSupportCrossOrigin() throws ServletException, IOException {
|
||||||
|
|
||||||
|
// We design test cases like this
|
||||||
|
// We start the Router and enable the Router to support Cross-origin.
|
||||||
|
// In the configuration, we allow example.com to access.
|
||||||
|
// 1. We simulate example.com and get the correct response
|
||||||
|
// 2. We simulate example.org and cannot get a response
|
||||||
|
|
||||||
|
// Initialize RouterWeb's CrossOrigin capability
|
||||||
|
Configuration conf = new Configuration();
|
||||||
|
conf.setBoolean(YarnConfiguration.ROUTER_WEBAPP_ENABLE_CORS_FILTER, true);
|
||||||
|
conf.set("hadoop.http.filter.initializers", HttpCrossOriginFilterInitializer.class.getName());
|
||||||
|
conf.set(HttpCrossOriginFilterInitializer.PREFIX + CrossOriginFilter.ALLOWED_ORIGINS,
|
||||||
|
"example.com");
|
||||||
|
conf.set(HttpCrossOriginFilterInitializer.PREFIX + CrossOriginFilter.ALLOWED_HEADERS,
|
||||||
|
"X-Requested-With,Accept");
|
||||||
|
conf.set(HttpCrossOriginFilterInitializer.PREFIX + CrossOriginFilter.ALLOWED_METHODS,
|
||||||
|
"GET,POST");
|
||||||
|
|
||||||
|
// Start the router
|
||||||
|
Router router = new Router();
|
||||||
|
router.init(conf);
|
||||||
|
router.start();
|
||||||
|
router.getServices();
|
||||||
|
|
||||||
|
// Get assigned to Filter.
|
||||||
|
// The name of the filter is "Cross Origin Filter",
|
||||||
|
// which is specified in HttpCrossOriginFilterInitializer.
|
||||||
|
WebApp webApp = router.getWebapp();
|
||||||
|
HttpServer2 httpServer2 = webApp.getHttpServer();
|
||||||
|
WebAppContext webAppContext = httpServer2.getWebAppContext();
|
||||||
|
ServletHandler servletHandler = webAppContext.getServletHandler();
|
||||||
|
FilterHolder holder = servletHandler.getFilter("Cross Origin Filter");
|
||||||
|
CrossOriginFilter filter = CrossOriginFilter.class.cast(holder.getFilter());
|
||||||
|
|
||||||
|
// 1. Simulate [example.com] for access
|
||||||
|
HttpServletRequest mockReq = Mockito.mock(HttpServletRequest.class);
|
||||||
|
Mockito.when(mockReq.getHeader("Origin")).thenReturn("example.com");
|
||||||
|
Mockito.when(mockReq.getHeader("Access-Control-Request-Method")).thenReturn("GET");
|
||||||
|
Mockito.when(mockReq.getHeader("Access-Control-Request-Headers"))
|
||||||
|
.thenReturn("X-Requested-With");
|
||||||
|
|
||||||
|
// Objects to verify interactions based on request
|
||||||
|
HttpServletResponseForRouterTest mockRes = new HttpServletResponseForRouterTest();
|
||||||
|
FilterChain mockChain = Mockito.mock(FilterChain.class);
|
||||||
|
|
||||||
|
// Object under test
|
||||||
|
filter.doFilter(mockReq, mockRes, mockChain);
|
||||||
|
|
||||||
|
// Why is 5, because when Filter passes,
|
||||||
|
// CrossOriginFilter will set 5 values to Map
|
||||||
|
Assert.assertEquals(5, mockRes.getHeaders().size());
|
||||||
|
String allowResult = mockRes.getHeader("Access-Control-Allow-Credentials");
|
||||||
|
Assert.assertEquals("true", allowResult);
|
||||||
|
|
||||||
|
// 2. Simulate [example.org] for access
|
||||||
|
HttpServletRequest mockReq2 = Mockito.mock(HttpServletRequest.class);
|
||||||
|
Mockito.when(mockReq2.getHeader("Origin")).thenReturn("example.org");
|
||||||
|
Mockito.when(mockReq2.getHeader("Access-Control-Request-Method")).thenReturn("GET");
|
||||||
|
Mockito.when(mockReq2.getHeader("Access-Control-Request-Headers"))
|
||||||
|
.thenReturn("X-Requested-With");
|
||||||
|
|
||||||
|
// Objects to verify interactions based on request
|
||||||
|
HttpServletResponseForRouterTest mockRes2 = new HttpServletResponseForRouterTest();
|
||||||
|
FilterChain mockChain2 = Mockito.mock(FilterChain.class);
|
||||||
|
|
||||||
|
// Object under test
|
||||||
|
filter.doFilter(mockReq2, mockRes2, mockChain2);
|
||||||
|
|
||||||
|
// Why is 0, because when the Filter fails,
|
||||||
|
// CrossOriginFilter will not set any value
|
||||||
|
Assert.assertEquals(0, mockRes2.getHeaders().size());
|
||||||
|
|
||||||
|
router.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class HttpServletResponseForRouterTest extends HttpServletResponseImpl {
|
||||||
|
private final Map<String, String> headers = new HashMap<>(1);
|
||||||
|
@Override
|
||||||
|
public void setHeader(String name, String value) {
|
||||||
|
headers.put(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHeader(String name) {
|
||||||
|
return headers.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getHeaders() {
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -284,6 +284,16 @@ Kerberos supported in federation.
|
||||||
| `yarn.router.kerberos.principal` | | The Router service principal. This is typically set to router/_HOST@REALM.TLD. Each Router will substitute _HOST with its own fully qualified hostname at startup. The _HOST placeholder allows using the same configuration setting on all Routers in setup. |
|
| `yarn.router.kerberos.principal` | | The Router service principal. This is typically set to router/_HOST@REALM.TLD. Each Router will substitute _HOST with its own fully qualified hostname at startup. The _HOST placeholder allows using the same configuration setting on all Routers in setup. |
|
||||||
| `yarn.router.kerberos.principal.hostname` | | Optional. The hostname for the Router containing this configuration file. Will be different for each machine. Defaults to current hostname. |
|
| `yarn.router.kerberos.principal.hostname` | | Optional. The hostname for the Router containing this configuration file. Will be different for each machine. Defaults to current hostname. |
|
||||||
|
|
||||||
|
Enabling CORS support:
|
||||||
|
|
||||||
|
To enable cross-origin support (CORS) for the Yarn Router, please set the following configuration parameters:
|
||||||
|
|
||||||
|
| Property | Example | Description |
|
||||||
|
| ----------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||||
|
| `hadoop.http.filter.initializers` | `org.apache.hadoop.security.HttpCrossOriginFilterInitializer` | Optional. Set the filter to HttpCrossOriginFilterInitializer, Configure this parameter in core-site.xml. |
|
||||||
|
| `yarn.router.webapp.cross-origin.enabled` | `true` | Optional. Enable/disable CORS filter.Configure this parameter in yarn-site.xml. |
|
||||||
|
|
||||||
|
|
||||||
###ON NMs:
|
###ON NMs:
|
||||||
|
|
||||||
These are extra configurations that should appear in the **conf/yarn-site.xml** at each NodeManager.
|
These are extra configurations that should appear in the **conf/yarn-site.xml** at each NodeManager.
|
||||||
|
|
|
@ -41,6 +41,7 @@ origin (CORS) support.
|
||||||
| `yarn.timeline-service.http-cross-origin.enabled` | true | Enable CORS support for Timeline Server |
|
| `yarn.timeline-service.http-cross-origin.enabled` | true | Enable CORS support for Timeline Server |
|
||||||
| `yarn.resourcemanager.webapp.cross-origin.enabled` | true | Enable CORS support for Resource Manager |
|
| `yarn.resourcemanager.webapp.cross-origin.enabled` | true | Enable CORS support for Resource Manager |
|
||||||
| `yarn.nodemanager.webapp.cross-origin.enabled` | true | Enable CORS support for Node Manager |
|
| `yarn.nodemanager.webapp.cross-origin.enabled` | true | Enable CORS support for Node Manager |
|
||||||
|
| `yarn.router.webapp.cross-origin.enabled` | true | Enable CORS support for Yarn Router |
|
||||||
|
|
||||||
Also please ensure that CORS related configurations are enabled in `core-site.xml`.
|
Also please ensure that CORS related configurations are enabled in `core-site.xml`.
|
||||||
Kindly refer [here](../../hadoop-project-dist/hadoop-common/HttpAuthentication.html)
|
Kindly refer [here](../../hadoop-project-dist/hadoop-common/HttpAuthentication.html)
|
||||||
|
|
Loading…
Reference in New Issue