YARN-4009. CORS support for ResourceManager REST API. ( Varun Vasudev via jeagles)
(cherry picked from commit f8adeb712d
)
This commit is contained in:
parent
7021e015d7
commit
49a7d70f53
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* 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.security;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.http.FilterContainer;
|
||||
import org.apache.hadoop.http.FilterInitializer;
|
||||
import org.apache.hadoop.security.http.CrossOriginFilter;
|
||||
|
||||
public class HttpCrossOriginFilterInitializer extends FilterInitializer {
|
||||
|
||||
public static final String PREFIX = "hadoop.http.cross-origin.";
|
||||
public static final String ENABLED_SUFFIX = "enabled";
|
||||
|
||||
private static final Log LOG =
|
||||
LogFactory.getLog(HttpCrossOriginFilterInitializer.class);
|
||||
|
||||
@Override
|
||||
public void initFilter(FilterContainer container, Configuration conf) {
|
||||
|
||||
String key = getEnabledConfigKey();
|
||||
boolean enabled = conf.getBoolean(key, false);
|
||||
if (enabled) {
|
||||
container.addGlobalFilter("Cross Origin Filter",
|
||||
CrossOriginFilter.class.getName(),
|
||||
getFilterParameters(conf, getPrefix()));
|
||||
} else {
|
||||
LOG.info("CORS filter not enabled. Please set " + key
|
||||
+ " to 'true' to enable it");
|
||||
}
|
||||
}
|
||||
|
||||
protected static Map<String, String> getFilterParameters(Configuration conf,
|
||||
String prefix) {
|
||||
Map<String, String> filterParams = new HashMap<String, String>();
|
||||
for (Map.Entry<String, String> entry : conf.getValByRegex(prefix)
|
||||
.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
name = name.substring(prefix.length());
|
||||
filterParams.put(name, value);
|
||||
}
|
||||
return filterParams;
|
||||
}
|
||||
|
||||
protected String getPrefix() {
|
||||
return HttpCrossOriginFilterInitializer.PREFIX;
|
||||
}
|
||||
|
||||
protected String getEnabledConfigKey() {
|
||||
return getPrefix() + HttpCrossOriginFilterInitializer.ENABLED_SUFFIX;
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hadoop.yarn.server.timeline.webapp;
|
||||
package org.apache.hadoop.security.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -246,7 +246,7 @@ public class CrossOriginFilter implements Filter {
|
|||
if (accessControlRequestHeaders == null) {
|
||||
return true;
|
||||
}
|
||||
String headers[] = accessControlRequestHeaders.trim().split("\\s*,\\s*");
|
||||
String[] headers = accessControlRequestHeaders.trim().split("\\s*,\\s*");
|
||||
return allowedHeaders.containsAll(Arrays.asList(headers));
|
||||
}
|
||||
|
|
@ -1311,6 +1311,42 @@ for ldap providers in the same way as above does.
|
|||
</description>
|
||||
</property>
|
||||
|
||||
<!-- HTTP CORS support -->
|
||||
<property>
|
||||
<description>Enable/disable the cross-origin (CORS) filter.</description>
|
||||
<name>hadoop.http.cross-origin.enabled</name>
|
||||
<value>false</value>
|
||||
</property>
|
||||
|
||||
<property>
|
||||
<description>Comma separated list of origins that are allowed for web
|
||||
services needing cross-origin (CORS) support. Wildcards (*) and patterns
|
||||
allowed</description>
|
||||
<name>hadoop.http.cross-origin.allowed-origins</name>
|
||||
<value>*</value>
|
||||
</property>
|
||||
|
||||
<property>
|
||||
<description>Comma separated list of methods that are allowed for web
|
||||
services needing cross-origin (CORS) support.</description>
|
||||
<name>hadoop.http.cross-origin.allowed-methods</name>
|
||||
<value>GET,POST,HEAD</value>
|
||||
</property>
|
||||
|
||||
<property>
|
||||
<description>Comma separated list of headers that are allowed for web
|
||||
services needing cross-origin (CORS) support.</description>
|
||||
<name>hadoop.http.cross-origin.allowed-headers</name>
|
||||
<value>X-Requested-With,Content-Type,Accept,Origin</value>
|
||||
</property>
|
||||
|
||||
<property>
|
||||
<description>The number of seconds a pre-flighted request can be cached
|
||||
for web services needing cross-origin (CORS) support.</description>
|
||||
<name>hadoop.http.cross-origin.max-age</name>
|
||||
<value>1800</value>
|
||||
</property>
|
||||
|
||||
<property>
|
||||
<name>dfs.ha.fencing.methods</name>
|
||||
<value></value>
|
||||
|
|
|
@ -56,3 +56,17 @@ IMPORTANT: when using IP addresses, browsers ignore cookies with domain settings
|
|||
`hadoop.http.authentication.kerberos.principal`: Indicates the Kerberos principal to be used for HTTP endpoint when using 'kerberos' authentication. The principal short name must be `HTTP` per Kerberos HTTP SPNEGO specification. The default value is `HTTP/_HOST@$LOCALHOST`, where `_HOST` -if present- is replaced with bind address of the HTTP server.
|
||||
|
||||
`hadoop.http.authentication.kerberos.keytab`: Location of the keytab file with the credentials for the Kerberos principal used for the HTTP endpoint. The default value is `$user.home/hadoop.keytab`.i
|
||||
|
||||
CORS
|
||||
----
|
||||
To enable cross-origin support (CORS), please set the following configuration parameters:
|
||||
|
||||
Add org.apache.hadoop.security.HttpCrossOriginFilterInitializer to hadoop.http.filter.initializers in core-site.xml. You will also need to set the following properties in core-site.xml -
|
||||
|
||||
| Property | Default Value | Description |
|
||||
|:---- |:---- |:---- |:---- |
|
||||
| hadoop.http.cross-origin.enabled | false | Enables cross origin support for all web-services |
|
||||
| hadoop.http.cross-origin.allowed-origins | \* | Comma separated list of origins that are allowed, wildcards (\*) and patterns allowed |
|
||||
| hadoop.http.cross-origin.allowed-methods | GET,POST,HEAD | Comma separated list of methods that are allowed |
|
||||
| hadoop.http.cross-origin.allowed-headers | X-Requested-With,Content-Type,Accept,Origin | Comma separated list of headers that are allowed |
|
||||
| hadoop.http.cross-origin.max-age | 1800 | Number of seconds a pre-flighted request can be cached |
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hadoop.yarn.server.timeline.webapp;
|
||||
package org.apache.hadoop.security;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -25,21 +25,22 @@ import org.apache.hadoop.conf.Configuration;
|
|||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestCrossOriginFilterInitializer {
|
||||
public class TestHttpCrossOriginFilterInitializer {
|
||||
|
||||
@Test
|
||||
public void testGetFilterParameters() {
|
||||
|
||||
// Initialize configuration object
|
||||
Configuration conf = new Configuration();
|
||||
conf.set(CrossOriginFilterInitializer.PREFIX + "rootparam", "rootvalue");
|
||||
conf.set(CrossOriginFilterInitializer.PREFIX + "nested.param",
|
||||
conf.set(HttpCrossOriginFilterInitializer.PREFIX + "rootparam",
|
||||
"rootvalue");
|
||||
conf.set(HttpCrossOriginFilterInitializer.PREFIX + "nested.param",
|
||||
"nestedvalue");
|
||||
conf.set("outofscopeparam", "outofscopevalue");
|
||||
|
||||
// call function under test
|
||||
Map<String, String> filterParameters =
|
||||
CrossOriginFilterInitializer.getFilterParameters(conf);
|
||||
Map<String, String> filterParameters = HttpCrossOriginFilterInitializer
|
||||
.getFilterParameters(conf, HttpCrossOriginFilterInitializer.PREFIX);
|
||||
|
||||
// retrieve values
|
||||
String rootvalue = filterParameters.get("rootparam");
|
|
@ -16,7 +16,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hadoop.yarn.server.timeline.webapp;
|
||||
package org.apache.hadoop.security.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
@ -31,13 +31,13 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.hadoop.security.http.CrossOriginFilter;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
|
||||
public class TestCrossOriginFilter {
|
||||
|
||||
|
@ -50,20 +50,20 @@ public class TestCrossOriginFilter {
|
|||
FilterConfig filterConfig = new FilterConfigTest(conf);
|
||||
|
||||
// Origin is not specified for same origin requests
|
||||
HttpServletRequest mockReq = mock(HttpServletRequest.class);
|
||||
when(mockReq.getHeader(CrossOriginFilter.ORIGIN)).thenReturn(null);
|
||||
HttpServletRequest mockReq = Mockito.mock(HttpServletRequest.class);
|
||||
Mockito.when(mockReq.getHeader(CrossOriginFilter.ORIGIN)).thenReturn(null);
|
||||
|
||||
// Objects to verify interactions based on request
|
||||
HttpServletResponse mockRes = mock(HttpServletResponse.class);
|
||||
FilterChain mockChain = mock(FilterChain.class);
|
||||
HttpServletResponse mockRes = Mockito.mock(HttpServletResponse.class);
|
||||
FilterChain mockChain = Mockito.mock(FilterChain.class);
|
||||
|
||||
// Object under test
|
||||
CrossOriginFilter filter = new CrossOriginFilter();
|
||||
filter.init(filterConfig);
|
||||
filter.doFilter(mockReq, mockRes, mockChain);
|
||||
|
||||
verifyZeroInteractions(mockRes);
|
||||
verify(mockChain).doFilter(mockReq, mockRes);
|
||||
Mockito.verifyZeroInteractions(mockRes);
|
||||
Mockito.verify(mockChain).doFilter(mockReq, mockRes);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -91,11 +91,12 @@ public class TestCrossOriginFilter {
|
|||
String encodedResponseSplitOrigin =
|
||||
CrossOriginFilter.encodeHeader(httpResponseSplitOrigin);
|
||||
Assert.assertEquals("Http response split origin should be protected against",
|
||||
validOrigin, encodedResponseSplitOrigin);
|
||||
validOrigin, encodedResponseSplitOrigin);
|
||||
|
||||
// Test Origin List
|
||||
String validOriginList = "http://foo.example.com:12345 http://bar.example.com:12345";
|
||||
String encodedValidOriginList = CrossOriginFilter.encodeHeader(validOriginList);
|
||||
String encodedValidOriginList = CrossOriginFilter
|
||||
.encodeHeader(validOriginList);
|
||||
Assert.assertEquals("Valid origin list encoding should match exactly",
|
||||
validOriginList, encodedValidOriginList);
|
||||
}
|
||||
|
@ -135,20 +136,20 @@ public class TestCrossOriginFilter {
|
|||
FilterConfig filterConfig = new FilterConfigTest(conf);
|
||||
|
||||
// Origin is not specified for same origin requests
|
||||
HttpServletRequest mockReq = mock(HttpServletRequest.class);
|
||||
when(mockReq.getHeader(CrossOriginFilter.ORIGIN)).thenReturn("example.org");
|
||||
HttpServletRequest mockReq = Mockito.mock(HttpServletRequest.class);
|
||||
Mockito.when(mockReq.getHeader(CrossOriginFilter.ORIGIN)).thenReturn("example.org");
|
||||
|
||||
// Objects to verify interactions based on request
|
||||
HttpServletResponse mockRes = mock(HttpServletResponse.class);
|
||||
FilterChain mockChain = mock(FilterChain.class);
|
||||
HttpServletResponse mockRes = Mockito.mock(HttpServletResponse.class);
|
||||
FilterChain mockChain = Mockito.mock(FilterChain.class);
|
||||
|
||||
// Object under test
|
||||
CrossOriginFilter filter = new CrossOriginFilter();
|
||||
filter.init(filterConfig);
|
||||
filter.doFilter(mockReq, mockRes, mockChain);
|
||||
|
||||
verifyZeroInteractions(mockRes);
|
||||
verify(mockChain).doFilter(mockReq, mockRes);
|
||||
Mockito.verifyZeroInteractions(mockRes);
|
||||
Mockito.verify(mockChain).doFilter(mockReq, mockRes);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -160,22 +161,23 @@ public class TestCrossOriginFilter {
|
|||
FilterConfig filterConfig = new FilterConfigTest(conf);
|
||||
|
||||
// Origin is not specified for same origin requests
|
||||
HttpServletRequest mockReq = mock(HttpServletRequest.class);
|
||||
when(mockReq.getHeader(CrossOriginFilter.ORIGIN)).thenReturn("example.com");
|
||||
when(mockReq.getHeader(CrossOriginFilter.ACCESS_CONTROL_REQUEST_METHOD))
|
||||
HttpServletRequest mockReq = Mockito.mock(HttpServletRequest.class);
|
||||
Mockito.when(mockReq.getHeader(CrossOriginFilter.ORIGIN)).thenReturn("example.com");
|
||||
Mockito.when(
|
||||
mockReq.getHeader(CrossOriginFilter.ACCESS_CONTROL_REQUEST_METHOD))
|
||||
.thenReturn("DISALLOWED_METHOD");
|
||||
|
||||
// Objects to verify interactions based on request
|
||||
HttpServletResponse mockRes = mock(HttpServletResponse.class);
|
||||
FilterChain mockChain = mock(FilterChain.class);
|
||||
HttpServletResponse mockRes = Mockito.mock(HttpServletResponse.class);
|
||||
FilterChain mockChain = Mockito.mock(FilterChain.class);
|
||||
|
||||
// Object under test
|
||||
CrossOriginFilter filter = new CrossOriginFilter();
|
||||
filter.init(filterConfig);
|
||||
filter.doFilter(mockReq, mockRes, mockChain);
|
||||
|
||||
verifyZeroInteractions(mockRes);
|
||||
verify(mockChain).doFilter(mockReq, mockRes);
|
||||
Mockito.verifyZeroInteractions(mockRes);
|
||||
Mockito.verify(mockChain).doFilter(mockReq, mockRes);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -187,24 +189,26 @@ public class TestCrossOriginFilter {
|
|||
FilterConfig filterConfig = new FilterConfigTest(conf);
|
||||
|
||||
// Origin is not specified for same origin requests
|
||||
HttpServletRequest mockReq = mock(HttpServletRequest.class);
|
||||
when(mockReq.getHeader(CrossOriginFilter.ORIGIN)).thenReturn("example.com");
|
||||
when(mockReq.getHeader(CrossOriginFilter.ACCESS_CONTROL_REQUEST_METHOD))
|
||||
HttpServletRequest mockReq = Mockito.mock(HttpServletRequest.class);
|
||||
Mockito.when(mockReq.getHeader(CrossOriginFilter.ORIGIN)).thenReturn("example.com");
|
||||
Mockito.when(
|
||||
mockReq.getHeader(CrossOriginFilter.ACCESS_CONTROL_REQUEST_METHOD))
|
||||
.thenReturn("GET");
|
||||
when(mockReq.getHeader(CrossOriginFilter.ACCESS_CONTROL_REQUEST_HEADERS))
|
||||
Mockito.when(
|
||||
mockReq.getHeader(CrossOriginFilter.ACCESS_CONTROL_REQUEST_HEADERS))
|
||||
.thenReturn("Disallowed-Header");
|
||||
|
||||
// Objects to verify interactions based on request
|
||||
HttpServletResponse mockRes = mock(HttpServletResponse.class);
|
||||
FilterChain mockChain = mock(FilterChain.class);
|
||||
HttpServletResponse mockRes = Mockito.mock(HttpServletResponse.class);
|
||||
FilterChain mockChain = Mockito.mock(FilterChain.class);
|
||||
|
||||
// Object under test
|
||||
CrossOriginFilter filter = new CrossOriginFilter();
|
||||
filter.init(filterConfig);
|
||||
filter.doFilter(mockReq, mockRes, mockChain);
|
||||
|
||||
verifyZeroInteractions(mockRes);
|
||||
verify(mockChain).doFilter(mockReq, mockRes);
|
||||
Mockito.verifyZeroInteractions(mockRes);
|
||||
Mockito.verify(mockChain).doFilter(mockReq, mockRes);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -216,32 +220,34 @@ public class TestCrossOriginFilter {
|
|||
FilterConfig filterConfig = new FilterConfigTest(conf);
|
||||
|
||||
// Origin is not specified for same origin requests
|
||||
HttpServletRequest mockReq = mock(HttpServletRequest.class);
|
||||
when(mockReq.getHeader(CrossOriginFilter.ORIGIN)).thenReturn("example.com");
|
||||
when(mockReq.getHeader(CrossOriginFilter.ACCESS_CONTROL_REQUEST_METHOD))
|
||||
HttpServletRequest mockReq = Mockito.mock(HttpServletRequest.class);
|
||||
Mockito.when(mockReq.getHeader(CrossOriginFilter.ORIGIN)).thenReturn("example.com");
|
||||
Mockito.when(
|
||||
mockReq.getHeader(CrossOriginFilter.ACCESS_CONTROL_REQUEST_METHOD))
|
||||
.thenReturn("GET");
|
||||
when(mockReq.getHeader(CrossOriginFilter.ACCESS_CONTROL_REQUEST_HEADERS))
|
||||
Mockito.when(
|
||||
mockReq.getHeader(CrossOriginFilter.ACCESS_CONTROL_REQUEST_HEADERS))
|
||||
.thenReturn("X-Requested-With");
|
||||
|
||||
// Objects to verify interactions based on request
|
||||
HttpServletResponse mockRes = mock(HttpServletResponse.class);
|
||||
FilterChain mockChain = mock(FilterChain.class);
|
||||
HttpServletResponse mockRes = Mockito.mock(HttpServletResponse.class);
|
||||
FilterChain mockChain = Mockito.mock(FilterChain.class);
|
||||
|
||||
// Object under test
|
||||
CrossOriginFilter filter = new CrossOriginFilter();
|
||||
filter.init(filterConfig);
|
||||
filter.doFilter(mockReq, mockRes, mockChain);
|
||||
|
||||
verify(mockRes).setHeader(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN,
|
||||
Mockito.verify(mockRes).setHeader(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN,
|
||||
"example.com");
|
||||
verify(mockRes).setHeader(
|
||||
Mockito.verify(mockRes).setHeader(
|
||||
CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS,
|
||||
Boolean.TRUE.toString());
|
||||
verify(mockRes).setHeader(CrossOriginFilter.ACCESS_CONTROL_ALLOW_METHODS,
|
||||
Mockito.verify(mockRes).setHeader(CrossOriginFilter.ACCESS_CONTROL_ALLOW_METHODS,
|
||||
filter.getAllowedMethodsHeader());
|
||||
verify(mockRes).setHeader(CrossOriginFilter.ACCESS_CONTROL_ALLOW_HEADERS,
|
||||
Mockito.verify(mockRes).setHeader(CrossOriginFilter.ACCESS_CONTROL_ALLOW_HEADERS,
|
||||
filter.getAllowedHeadersHeader());
|
||||
verify(mockChain).doFilter(mockReq, mockRes);
|
||||
Mockito.verify(mockChain).doFilter(mockReq, mockRes);
|
||||
}
|
||||
|
||||
@Test
|
|
@ -8,6 +8,8 @@ Release 2.7.2 - UNRELEASED
|
|||
|
||||
IMPROVEMENTS
|
||||
|
||||
YARN-4009. CORS support for ResourceManager REST API. ( Varun Vasudev via jeagles)
|
||||
|
||||
YARN-3170. YARN architecture document needs updating. (Brahma Reddy Battula
|
||||
via ozawa)
|
||||
|
||||
|
|
|
@ -333,6 +333,11 @@ public class YarnConfiguration extends Configuration {
|
|||
public static final boolean DEFAULT_RM_WEBAPP_DELEGATION_TOKEN_AUTH_FILTER =
|
||||
true;
|
||||
|
||||
/** Enable cross origin (CORS) support. **/
|
||||
public static final String RM_WEBAPP_ENABLE_CORS_FILTER =
|
||||
RM_PREFIX + "webapp.cross-origin.enabled";
|
||||
public static final boolean DEFAULT_RM_WEBAPP_ENABLE_CORS_FILTER = false;
|
||||
|
||||
/** How long to wait until a container is considered dead.*/
|
||||
public static final String RM_CONTAINER_ALLOC_EXPIRY_INTERVAL_MS =
|
||||
RM_PREFIX + "rm.container-allocation.expiry-interval-ms";
|
||||
|
@ -852,7 +857,12 @@ public class YarnConfiguration extends Configuration {
|
|||
public static final int DEFAULT_NM_WEBAPP_HTTPS_PORT = 8044;
|
||||
public static final String DEFAULT_NM_WEBAPP_HTTPS_ADDRESS = "0.0.0.0:"
|
||||
+ DEFAULT_NM_WEBAPP_HTTPS_PORT;
|
||||
|
||||
|
||||
/** Enable/disable CORS filter. */
|
||||
public static final String NM_WEBAPP_ENABLE_CORS_FILTER =
|
||||
NM_PREFIX + "webapp.cross-origin.enabled";
|
||||
public static final boolean DEFAULT_NM_WEBAPP_ENABLE_CORS_FILTER = false;
|
||||
|
||||
/** How often to monitor containers.*/
|
||||
public final static String NM_CONTAINER_MON_INTERVAL_MS =
|
||||
NM_PREFIX + "container-monitor.interval-ms";
|
||||
|
|
|
@ -218,6 +218,14 @@
|
|||
<value>true</value>
|
||||
</property>
|
||||
|
||||
<property>
|
||||
<description>Flag to enable cross-origin (CORS) support in the RM. This flag
|
||||
requires the CORS filter initializer to be added to the filter initializers
|
||||
list in core-site.xml.</description>
|
||||
<name>yarn.resourcemanager.webapp.cross-origin.enabled</name>
|
||||
<value>false</value>
|
||||
</property>
|
||||
|
||||
<property>
|
||||
<description>How long to wait until a node manager is considered dead.</description>
|
||||
<name>yarn.nm.liveness-monitor.expiry-interval-ms</name>
|
||||
|
@ -1671,4 +1679,12 @@
|
|||
<name>yarn.nodemanager.log-aggregation.roll-monitoring-interval-seconds</name>
|
||||
<value>-1</value>
|
||||
</property>
|
||||
|
||||
<property>
|
||||
<description>Flag to enable cross-origin (CORS) support in the NM. This flag
|
||||
requires the CORS filter initializer to be added to the filter initializers
|
||||
list in core-site.xml.</description>
|
||||
<name>yarn.nodemanager.webapp.cross-origin.enabled</name>
|
||||
<value>false</value>
|
||||
</property>
|
||||
</configuration>
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.apache.hadoop.http.HttpServer2;
|
|||
import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
|
||||
import org.apache.hadoop.metrics2.source.JvmMetrics;
|
||||
import org.apache.hadoop.security.AuthenticationFilterInitializer;
|
||||
import org.apache.hadoop.security.HttpCrossOriginFilterInitializer;
|
||||
import org.apache.hadoop.security.SecurityUtil;
|
||||
import org.apache.hadoop.service.CompositeService;
|
||||
import org.apache.hadoop.service.Service;
|
||||
|
@ -242,10 +243,17 @@ public class ApplicationHistoryServer extends CompositeService {
|
|||
if(conf.getBoolean(YarnConfiguration
|
||||
.TIMELINE_SERVICE_HTTP_CROSS_ORIGIN_ENABLED, YarnConfiguration
|
||||
.TIMELINE_SERVICE_HTTP_CROSS_ORIGIN_ENABLED_DEFAULT)) {
|
||||
if (initializers.length() != 0) {
|
||||
initializers += ",";
|
||||
if (initializers.contains(HttpCrossOriginFilterInitializer.class.getName())) {
|
||||
initializers =
|
||||
initializers.replaceAll(HttpCrossOriginFilterInitializer.class.getName(),
|
||||
CrossOriginFilterInitializer.class.getName());
|
||||
}
|
||||
else {
|
||||
if (initializers.length() != 0) {
|
||||
initializers += ",";
|
||||
}
|
||||
initializers += CrossOriginFilterInitializer.class.getName();
|
||||
}
|
||||
initializers += CrossOriginFilterInitializer.class.getName();
|
||||
modifiedInitializers = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,35 +18,35 @@
|
|||
|
||||
package org.apache.hadoop.yarn.server.timeline.webapp;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.http.FilterContainer;
|
||||
import org.apache.hadoop.http.FilterInitializer;
|
||||
import org.apache.hadoop.security.HttpCrossOriginFilterInitializer;
|
||||
import org.apache.hadoop.security.http.CrossOriginFilter;
|
||||
|
||||
public class CrossOriginFilterInitializer extends FilterInitializer {
|
||||
import java.util.Map;
|
||||
|
||||
public class CrossOriginFilterInitializer extends HttpCrossOriginFilterInitializer {
|
||||
|
||||
public static final String PREFIX =
|
||||
"yarn.timeline-service.http-cross-origin.";
|
||||
|
||||
@Override
|
||||
protected String getPrefix() {
|
||||
return PREFIX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initFilter(FilterContainer container, Configuration conf) {
|
||||
|
||||
container.addGlobalFilter("Cross Origin Filter",
|
||||
CrossOriginFilter.class.getName(), getFilterParameters(conf));
|
||||
}
|
||||
// setup the filter
|
||||
// use the keys with "yarn.timeline-service.http-cross-origin" prefix to
|
||||
// override the ones with the "hadoop.http.cross-origin" prefix.
|
||||
|
||||
static Map<String, String> getFilterParameters(Configuration conf) {
|
||||
Map<String, String> filterParams =
|
||||
new HashMap<String, String>();
|
||||
for (Map.Entry<String, String> entry : conf.getValByRegex(PREFIX)
|
||||
.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
name = name.substring(PREFIX.length());
|
||||
filterParams.put(name, value);
|
||||
}
|
||||
return filterParams;
|
||||
Map<String, String> filterParameters =
|
||||
getFilterParameters(conf, HttpCrossOriginFilterInitializer.PREFIX);
|
||||
filterParameters.putAll(getFilterParameters(conf, getPrefix()));
|
||||
|
||||
container.addGlobalFilter("Cross Origin Filter",
|
||||
CrossOriginFilter.class.getName(), filterParameters);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -81,6 +81,11 @@
|
|||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.zookeeper</groupId>
|
||||
<artifactId>zookeeper</artifactId>
|
||||
|
|
|
@ -23,6 +23,7 @@ import static org.apache.hadoop.yarn.util.StringHelper.pajoin;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.hadoop.http.HttpConfig;
|
||||
import org.apache.hadoop.security.HttpCrossOriginFilterInitializer;
|
||||
import org.apache.hadoop.service.AbstractService;
|
||||
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
||||
import org.apache.hadoop.yarn.exceptions.YarnRuntimeException;
|
||||
|
@ -58,7 +59,14 @@ public class WebServer extends AbstractService {
|
|||
String bindAddress = WebAppUtils.getWebAppBindURL(getConfig(),
|
||||
YarnConfiguration.NM_BIND_HOST,
|
||||
WebAppUtils.getNMWebAppURLWithoutScheme(getConfig()));
|
||||
|
||||
boolean enableCors = getConfig()
|
||||
.getBoolean(YarnConfiguration.NM_WEBAPP_ENABLE_CORS_FILTER,
|
||||
YarnConfiguration.DEFAULT_NM_WEBAPP_ENABLE_CORS_FILTER);
|
||||
if (enableCors) {
|
||||
getConfig().setBoolean(HttpCrossOriginFilterInitializer.PREFIX
|
||||
+ HttpCrossOriginFilterInitializer.ENABLED_SUFFIX, true);
|
||||
}
|
||||
|
||||
LOG.info("Instantiating NMWebApp at " + bindAddress);
|
||||
try {
|
||||
this.webApp =
|
||||
|
|
|
@ -28,10 +28,7 @@ import org.apache.hadoop.ha.HAServiceProtocol.HAServiceState;
|
|||
import org.apache.hadoop.http.lib.StaticUserWebFilter;
|
||||
import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
|
||||
import org.apache.hadoop.metrics2.source.JvmMetrics;
|
||||
import org.apache.hadoop.security.AuthenticationFilterInitializer;
|
||||
import org.apache.hadoop.security.Groups;
|
||||
import org.apache.hadoop.security.SecurityUtil;
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.hadoop.security.*;
|
||||
import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler;
|
||||
import org.apache.hadoop.security.authorize.ProxyUsers;
|
||||
import org.apache.hadoop.service.AbstractService;
|
||||
|
@ -841,6 +838,9 @@ public class ResourceManager extends CompositeService implements Recoverable {
|
|||
// 4. hadoop.http.filter.initializers container AuthenticationFilterInitializer
|
||||
|
||||
Configuration conf = getConfig();
|
||||
boolean enableCorsFilter =
|
||||
conf.getBoolean(YarnConfiguration.RM_WEBAPP_ENABLE_CORS_FILTER,
|
||||
YarnConfiguration.DEFAULT_RM_WEBAPP_ENABLE_CORS_FILTER);
|
||||
boolean useYarnAuthenticationFilter =
|
||||
conf.getBoolean(
|
||||
YarnConfiguration.RM_WEBAPP_DELEGATION_TOKEN_AUTH_FILTER,
|
||||
|
@ -852,6 +852,12 @@ public class ResourceManager extends CompositeService implements Recoverable {
|
|||
Class<?>[] initializersClasses =
|
||||
conf.getClasses(filterInitializerConfKey);
|
||||
|
||||
// setup CORS
|
||||
if (enableCorsFilter) {
|
||||
conf.setBoolean(HttpCrossOriginFilterInitializer.PREFIX
|
||||
+ HttpCrossOriginFilterInitializer.ENABLED_SUFFIX, true);
|
||||
}
|
||||
|
||||
boolean hasHadoopAuthFilterInitializer = false;
|
||||
boolean hasRMAuthFilterInitializer = false;
|
||||
if (initializersClasses != null) {
|
||||
|
|
|
@ -16,6 +16,7 @@ NodeManager REST API's
|
|||
=======================
|
||||
|
||||
* [Overview](#Overview)
|
||||
* [Enabling CORS support](#Enabling_CORS_support)
|
||||
* [NodeManager Information API](#NodeManager_Information_API)
|
||||
* [Applications API](#Applications_API)
|
||||
* [Application API](#Application_API)
|
||||
|
@ -27,6 +28,13 @@ Overview
|
|||
|
||||
The NodeManager REST API's allow the user to get status on the node and information about applications and containers running on that node.
|
||||
|
||||
Enabling CORS support
|
||||
---------------------
|
||||
To enable cross-origin support (CORS) for the NM only(without enabling it for the RM), please set the following configuration parameters:
|
||||
|
||||
In core-site.xml, add org.apache.hadoop.security.HttpCrossOriginFilterInitializer to hadoop.http.filter.initializers.
|
||||
In yarn-site.xml, set yarn.nodemanager.webapp.cross-origin.enabled to true.
|
||||
|
||||
NodeManager Information API
|
||||
---------------------------
|
||||
|
||||
|
@ -540,4 +548,4 @@ Response Body:
|
|||
<containerLogsLink>http://host.domain.com:8042/node/containerlogs/container_1326121700862_0007_01_000001/user1</containerLogsLink>
|
||||
<nodeId>host.domain.com:8041</nodeId>
|
||||
</container>
|
||||
```
|
||||
```
|
||||
|
|
|
@ -16,6 +16,7 @@ ResourceManager REST API's.
|
|||
===========================
|
||||
|
||||
* [Overview](#Overview)
|
||||
* [Enabling CORS support](#Enabling_CORS_support)
|
||||
* [Cluster Information API](#Cluster_Information_API)
|
||||
* [Cluster Metrics API](#Cluster_Metrics_API)
|
||||
* [Cluster Scheduler API](#Cluster_Scheduler_API)
|
||||
|
@ -37,6 +38,13 @@ Overview
|
|||
|
||||
The ResourceManager REST API's allow the user to get information about the cluster - status on the cluster, metrics on the cluster, scheduler information, information about nodes in the cluster, and information about applications on the cluster.
|
||||
|
||||
Enabling CORS support
|
||||
---------------------
|
||||
To enable cross-origin support (CORS) for the RM only(without enabling it for the NM), please set the following configuration parameters:
|
||||
|
||||
In core-site.xml, add org.apache.hadoop.security.HttpCrossOriginFilterInitializer to hadoop.http.filter.initializers.
|
||||
In yarn-site.xml, set yarn.resourcemanager.webapp.cross-origin.enabled to true.
|
||||
|
||||
Cluster Information API
|
||||
-----------------------
|
||||
|
||||
|
|
Loading…
Reference in New Issue