Commit de16cb71 by Gregor Zurowski Committed by Spencer Gibb

Add new filters actuator endpoint (#2244)

* Add new Zuul filters endpoint and refactor routes endpoint * Refactor FiltersEndpoint - Extend from AbstractEndpoint and simplify code - Move tests classes into package endpoint - Remove usage of Lombok * Conditionally enable Zuul routes and filters endpoints * Provide FilterRegistry to FiltersEndpoint via constructor
parent ffc43175
......@@ -1700,11 +1700,17 @@ Security. The assumption in this case is that the downstream services
might add these headers too, and we want the values from the proxy.
To not discard these well known security headers in case Spring Security is on the classpath you can set `zuul.ignoreSecurityHeaders` to `false`. This can be useful if you disabled the HTTP Security response headers in Spring Security and want the values provided by downstream services
=== The Routes Endpoint
=== Management Endpoints
If you are using `@EnableZuulProxy` with tha Spring Boot Actuator you
will enable (by default) an additional endpoint, available via HTTP as
`/routes`. A GET to this endpoint will return a list of the mapped
If you are using `@EnableZuulProxy` with the Spring Boot Actuator you
will enable (by default) two additional endpoints:
* Routes
* Filters
==== Routes Endpoint
A GET to the routes endpoint at `/routes` will return a list of the mapped
routes:
.GET /routes
......@@ -1743,6 +1749,12 @@ NOTE: the routes should respond automatically to changes in the
service catalog, but the POST to /routes is a way to force the change
to happen immediately.
==== Filters Endpoint
A GET to the filters endpoint at `/filters` will return a map of Zuul
filters by type. For each filter type in the map, you will find a list
of all the filters of that type, along with their details.
=== Strangulation Patterns and Local Forwards
A common pattern when migrating an existing application or API is to
......
package org.springframework.cloud.netflix.zuul;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.filters.FilterRegistry;
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* Endpoint for listing Zuul filters.
*
* @author Daryl Robbins
* @author Gregor Zurowski
*/
@ManagedResource(description = "List Zuul filters")
public class FiltersEndpoint extends AbstractEndpoint<Map<String, List<Map<String, Object>>>> {
private static final String ID = "filters";
private final FilterRegistry filterRegistry;
public FiltersEndpoint(FilterRegistry filterRegistry) {
super(ID, true);
this.filterRegistry = filterRegistry;
}
@ManagedAttribute
@Override
public Map<String, List<Map<String, Object>>> invoke() {
// Map of filters by type
final Map<String, List<Map<String, Object>>> filterMap = new TreeMap<>();
for (ZuulFilter filter : this.filterRegistry.getAllFilters()) {
// Ensure that we have a list to store filters of each type
if (!filterMap.containsKey(filter.filterType())) {
filterMap.put(filter.filterType(), new ArrayList<Map<String, Object>>());
}
final Map<String, Object> filterInfo = new LinkedHashMap<>();
filterInfo.put("class", filter.getClass().getName());
filterInfo.put("order", filter.filterOrder());
filterInfo.put("disabled", filter.isFilterDisabled());
filterInfo.put("static", filter.isStaticFilter());
filterMap.get(filter.filterType()).add(filterInfo);
}
return filterMap;
}
}
......@@ -19,8 +19,10 @@ package org.springframework.cloud.netflix.zuul;
import java.util.Collections;
import java.util.List;
import com.netflix.zuul.filters.FilterRegistry;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.trace.TraceRepository;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
......@@ -158,22 +160,31 @@ public class ZuulProxyAutoConfiguration extends ZuulServerAutoConfiguration {
@Configuration
@ConditionalOnClass(Endpoint.class)
protected static class RoutesEndpointConfiguration {
protected static class EndpointConfiguration {
@Autowired(required = false)
private TraceRepository traces;
@ConditionalOnEnabledEndpoint("routes")
@Bean
public RoutesEndpoint zuulEndpoint(RouteLocator routeLocator) {
public RoutesEndpoint routesEndpoint(RouteLocator routeLocator) {
return new RoutesEndpoint(routeLocator);
}
@ConditionalOnEnabledEndpoint("routes")
@Bean
public RoutesMvcEndpoint zuulMvcEndpoint(RouteLocator routeLocator,
public RoutesMvcEndpoint routesMvcEndpoint(RouteLocator routeLocator,
RoutesEndpoint endpoint) {
return new RoutesMvcEndpoint(endpoint, routeLocator);
}
@ConditionalOnEnabledEndpoint("filters")
@Bean
public FiltersEndpoint filtersEndpoint() {
FilterRegistry filterRegistry = FilterRegistry.instance();
return new FiltersEndpoint(filterRegistry);
}
@Bean
public ProxyRequestHelper proxyRequestHelper(ZuulProperties zuulProperties) {
TraceProxyRequestHelper helper = new TraceProxyRequestHelper();
......
package org.springframework.cloud.netflix.zuul;
import com.netflix.zuul.ZuulFilter;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
import static org.hibernate.validator.internal.util.Contracts.assertTrue;
import static org.junit.Assert.assertEquals;
/**
* Tests for Filters endpoint
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = FiltersEndpointApplication.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
value = { "server.contextPath: /app" })
public class FiltersEndpointTests {
@Autowired
private FiltersEndpoint endpoint;
@Test
public void getFilters() {
final Map<String, List<Map<String, Object>>> filters = endpoint.invoke();
boolean foundFilter = false;
if (filters.containsKey("sample")) {
for (Map<String, Object> filterInfo : filters.get("sample")) {
if (TestFilter.class.getName().equals(filterInfo.get("class"))) {
foundFilter = true;
// Verify filter's attributes
assertEquals(0, filterInfo.get("order"));
break; // the search is over
}
}
}
assertTrue(foundFilter, "Could not find expected sample filter from filters endpoint");
}
}
@Configuration
@EnableAutoConfiguration
@RestController
@EnableZuulProxy
class FiltersEndpointApplication {
@Bean
public ZuulFilter sampleFilter() {
return new TestFilter();
}
}
class TestFilter extends ZuulFilter {
@Override
public String filterType() {
return "sample";
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
return null;
}
@Override
public int filterOrder() {
return 0;
}
}
\ No newline at end of file
......@@ -25,6 +25,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.netflix.zuul.RoutesEndpoint;
import org.springframework.cloud.netflix.zuul.RoutesRefreshedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ParameterizedTypeReference;
......
......@@ -26,6 +26,7 @@ import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.cloud.netflix.zuul.RoutesEndpoint;
import org.springframework.cloud.netflix.zuul.filters.Route;
import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
......
......@@ -30,6 +30,9 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.netflix.zuul.RoutesEndpoint;
import org.springframework.cloud.netflix.zuul.RoutesRefreshedEvent;
import org.springframework.cloud.netflix.zuul.RoutesMvcEndpoint;
import org.springframework.cloud.netflix.zuul.filters.Route;
import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
import org.springframework.context.ApplicationEventPublisher;
......
......@@ -25,7 +25,6 @@ import com.netflix.zuul.context.RequestContext;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
......
......@@ -23,12 +23,9 @@ import com.netflix.zuul.context.RequestContext;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
......@@ -42,7 +39,6 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.cloud.commons.httpclient.ApacheHttpClientConnectionManagerFactory;
import org.springframework.cloud.commons.httpclient.ApacheHttpClientFactory;
import org.springframework.cloud.commons.httpclient.DefaultApacheHttpClientFactory;
import org.springframework.cloud.netflix.feign.ribbon.FeignRibbonClientAutoConfiguration;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment