Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
spring-cloud-netflix
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
openSource
spring-cloud-netflix
Commits
ffc33b4c
Commit
ffc33b4c
authored
Jul 12, 2017
by
Ryan Baxter
Committed by
GitHub
Jul 12, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2105 from gzurowski/routes-endpoint-details
Provide more Zuul route details in the routes actuator endpoint
parents
1d3773ab
781fa3ea
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
219 additions
and
4 deletions
+219
-4
spring-cloud-netflix.adoc
docs/src/main/asciidoc/spring-cloud-netflix.adoc
+31
-1
RoutesEndpoint.java
...rg/springframework/cloud/netflix/zuul/RoutesEndpoint.java
+113
-0
RoutesMvcEndpoint.java
...springframework/cloud/netflix/zuul/RoutesMvcEndpoint.java
+26
-1
RoutesEndpointIntegrationTests.java
...rk/cloud/netflix/zuul/RoutesEndpointIntegrationTests.java
+23
-0
RoutesEndpointTests.java
...ringframework/cloud/netflix/zuul/RoutesEndpointTests.java
+12
-1
RoutesMvcEndpointTests.java
...gframework/cloud/netflix/zuul/RoutesMvcEndpointTests.java
+14
-1
No files found.
docs/src/main/asciidoc/spring-cloud-netflix.adoc
View file @
ffc33b4c
...
...
@@ -1656,7 +1656,37 @@ To not discard these well known security headers in case Spring Security is on t
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
routes
.
A
POST
will
force
a
refresh
of
the
existing
routes
(
e
.
g
.
in
routes
:
.
GET
/
routes
[
source
,
json
]
----
{
/
stores
/**:
"http://localhost:8081"
}
----
Additional
route
details
can
be
requested
by
adding
the
`?
format
=
details
`
query
string
to
`/
routes
`.
This
will
produce
the
following
output
:
.
GET
/
routes
?
format
=
details
[
source
,
json
]
----
{
"/stores/**"
:
{
"id"
:
"stores"
,
"fullPath"
:
"/stores/**"
,
"location"
:
"http://localhost:8081"
,
"path"
:
"/**"
,
"prefix"
:
"/stores"
,
"retryable"
:
false
,
"customSensitiveHeaders"
:
false
,
"prefixStripped"
:
true
}
}
----
A
POST
will
force
a
refresh
of
the
existing
routes
(
e
.
g
.
in
case
there
have
been
changes
in
the
service
catalog
).
You
can
disable
this
endpoint
by
setting
`
endpoints
.
routes
.
enabled
`
to
`
false
`.
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/RoutesEndpoint.java
View file @
ffc33b4c
...
...
@@ -18,7 +18,11 @@ package org.springframework.cloud.netflix.zuul;
import
java.util.LinkedHashMap
;
import
java.util.Map
;
import
java.util.Objects
;
import
java.util.Set
;
import
com.fasterxml.jackson.annotation.JsonInclude
;
import
com.fasterxml.jackson.annotation.JsonPropertyOrder
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.actuate.endpoint.AbstractEndpoint
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
...
...
@@ -34,6 +38,7 @@ import org.springframework.jmx.export.annotation.ManagedResource;
* @author Spencer Gibb
* @author Dave Syer
* @author Ryan Baxter
* @author Gregor Zurowski
*/
@ManagedResource
(
description
=
"Can be used to list the reverse proxy routes"
)
@ConfigurationProperties
(
prefix
=
"endpoints.routes"
)
...
...
@@ -59,4 +64,112 @@ public class RoutesEndpoint extends AbstractEndpoint<Map<String, String>> {
}
return
map
;
}
Map
<
String
,
RouteDetails
>
invokeRouteDetails
()
{
Map
<
String
,
RouteDetails
>
map
=
new
LinkedHashMap
<>();
for
(
Route
route
:
this
.
routes
.
getRoutes
())
{
map
.
put
(
route
.
getFullPath
(),
new
RouteDetails
(
route
));
}
return
map
;
}
/**
* Container for exposing Zuul {@link Route} details as JSON.
*/
@JsonPropertyOrder
({
"id"
,
"fullPath"
,
"location"
})
@JsonInclude
(
JsonInclude
.
Include
.
NON_EMPTY
)
public
static
class
RouteDetails
{
private
String
id
;
private
String
fullPath
;
private
String
path
;
private
String
location
;
private
String
prefix
;
private
Boolean
retryable
;
private
Set
<
String
>
sensitiveHeaders
;
private
boolean
customSensitiveHeaders
;
private
boolean
prefixStripped
;
public
RouteDetails
()
{
}
RouteDetails
(
final
Route
route
)
{
this
.
id
=
route
.
getId
();
this
.
fullPath
=
route
.
getFullPath
();
this
.
path
=
route
.
getPath
();
this
.
location
=
route
.
getLocation
();
this
.
prefix
=
route
.
getPrefix
();
this
.
retryable
=
route
.
getRetryable
();
this
.
sensitiveHeaders
=
route
.
getSensitiveHeaders
();
this
.
customSensitiveHeaders
=
route
.
isCustomSensitiveHeaders
();
this
.
prefixStripped
=
route
.
isPrefixStripped
();
}
public
String
getId
()
{
return
id
;
}
public
String
getFullPath
()
{
return
fullPath
;
}
public
String
getPath
()
{
return
path
;
}
public
String
getLocation
()
{
return
location
;
}
public
String
getPrefix
()
{
return
prefix
;
}
public
Boolean
getRetryable
()
{
return
retryable
;
}
public
Set
<
String
>
getSensitiveHeaders
()
{
return
sensitiveHeaders
;
}
public
boolean
isCustomSensitiveHeaders
()
{
return
customSensitiveHeaders
;
}
public
boolean
isPrefixStripped
()
{
return
prefixStripped
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
return
true
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
RouteDetails
that
=
(
RouteDetails
)
o
;
return
Objects
.
equals
(
id
,
that
.
id
)
&&
Objects
.
equals
(
fullPath
,
that
.
fullPath
)
&&
Objects
.
equals
(
path
,
that
.
path
)
&&
Objects
.
equals
(
location
,
that
.
location
)
&&
Objects
.
equals
(
prefix
,
that
.
prefix
)
&&
Objects
.
equals
(
retryable
,
that
.
retryable
)
&&
Objects
.
equals
(
sensitiveHeaders
,
that
.
sensitiveHeaders
)
&&
customSensitiveHeaders
==
that
.
customSensitiveHeaders
&&
prefixStripped
==
that
.
prefixStripped
;
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
id
,
fullPath
,
path
,
location
,
prefix
,
retryable
,
sensitiveHeaders
,
customSensitiveHeaders
,
prefixStripped
);
}
}
}
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/RoutesMvcEndpoint.java
View file @
ffc33b4c
...
...
@@ -18,28 +18,38 @@
package
org
.
springframework
.
cloud
.
netflix
.
zuul
;
import
org.springframework.boot.actuate.endpoint.mvc.ActuatorMediaTypes
;
import
org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter
;
import
org.springframework.cloud.netflix.zuul.filters.Route
;
import
org.springframework.cloud.netflix.zuul.filters.RouteLocator
;
import
org.springframework.context.ApplicationEventPublisher
;
import
org.springframework.context.ApplicationEventPublisherAware
;
import
org.springframework.http.MediaType
;
import
org.springframework.jmx.export.annotation.ManagedOperation
;
import
org.springframework.jmx.export.annotation.ManagedResource
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.bind.annotation.ResponseBody
;
/**
* Endpoint used to reset the reverse proxy routes
* @author Ryan Baxter
* @author Gregor Zurowski
*/
@ManagedResource
(
description
=
"Can be used to reset the reverse proxy routes"
)
public
class
RoutesMvcEndpoint
extends
EndpointMvcAdapter
implements
ApplicationEventPublisherAware
{
static
final
String
FORMAT_DETAILS
=
"details"
;
private
final
RoutesEndpoint
endpoint
;
private
RouteLocator
routes
;
private
ApplicationEventPublisher
publisher
;
public
RoutesMvcEndpoint
(
RoutesEndpoint
endpoint
,
RouteLocator
routes
)
{
super
(
endpoint
);
this
.
endpoint
=
endpoint
;
this
.
routes
=
routes
;
}
...
...
@@ -55,4 +65,18 @@ public class RoutesMvcEndpoint extends EndpointMvcAdapter implements Application
this
.
publisher
.
publishEvent
(
new
RoutesRefreshedEvent
(
this
.
routes
));
return
super
.
invoke
();
}
}
/**
* Expose Zuul {@link Route} information with details.
*/
@GetMapping
(
params
=
"format"
,
produces
=
{
ActuatorMediaTypes
.
APPLICATION_ACTUATOR_V1_JSON_VALUE
,
MediaType
.
APPLICATION_JSON_VALUE
})
@ResponseBody
public
Object
invokeRouteDetails
(
@RequestParam
String
format
)
{
if
(
FORMAT_DETAILS
.
equalsIgnoreCase
(
format
))
{
return
endpoint
.
invokeRouteDetails
();
}
else
{
return
super
.
invoke
();
}
}
}
\ No newline at end of file
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/RoutesEndpointIntegrationTests.java
View file @
ffc33b4c
...
...
@@ -27,16 +27,23 @@ import org.springframework.boot.test.context.SpringBootTest;
import
org.springframework.boot.test.web.client.TestRestTemplate
;
import
org.springframework.context.ApplicationListener
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.core.ParameterizedTypeReference
;
import
org.springframework.http.HttpMethod
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.stereotype.Component
;
import
org.springframework.test.annotation.DirtiesContext
;
import
org.springframework.test.context.junit4.SpringJUnit4ClassRunner
;
import
org.springframework.web.bind.annotation.RestController
;
import
static
org
.
hamcrest
.
Matchers
.
is
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertThat
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
/**
* @author Ryan Baxter
* @author Gregor Zurowski
*/
@RunWith
(
SpringJUnit4ClassRunner
.
class
)
@SpringBootTest
(
...
...
@@ -64,6 +71,22 @@ public class RoutesEndpointIntegrationTests {
assertTrue
(
refreshListener
.
wasCalled
());
}
@Test
public
void
getRouteDetailsTest
()
{
ResponseEntity
<
Map
<
String
,
RoutesEndpoint
.
RouteDetails
>>
responseEntity
=
restTemplate
.
exchange
(
"/admin/routes?format=details"
,
HttpMethod
.
GET
,
null
,
new
ParameterizedTypeReference
<
Map
<
String
,
RoutesEndpoint
.
RouteDetails
>>()
{
});
assertThat
(
responseEntity
.
getStatusCode
(),
is
(
HttpStatus
.
OK
));
RoutesEndpoint
.
RouteDetails
details
=
responseEntity
.
getBody
().
get
(
"/sslservice/**"
);
assertThat
(
details
.
getPath
(),
is
(
"/**"
));
assertThat
(
details
.
getFullPath
(),
is
(
"/sslservice/**"
));
assertThat
(
details
.
getLocation
(),
is
(
"https://localhost:8443"
));
assertThat
(
details
.
getPrefix
(),
is
(
"/sslservice"
));
assertTrue
(
details
.
isPrefixStripped
());
}
@Configuration
@EnableAutoConfiguration
@RestController
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/RoutesEndpointTests.java
View file @
ffc33b4c
...
...
@@ -34,6 +34,7 @@ import static org.junit.Assert.assertTrue;
/**
* @author Ryan Baxter
* @author Gregor Zurowski
*/
public
class
RoutesEndpointTests
{
...
...
@@ -51,7 +52,7 @@ public class RoutesEndpointTests {
public
List
<
Route
>
getRoutes
()
{
List
<
Route
>
routes
=
new
ArrayList
<>();
routes
.
add
(
new
Route
(
"foo"
,
"foopath"
,
"foolocation"
,
null
,
true
,
Collections
.
EMPTY_SET
));
routes
.
add
(
new
Route
(
"bar"
,
"barpath"
,
"barlocation"
,
null
,
true
,
Collections
.
EMPTY_SET
));
routes
.
add
(
new
Route
(
"bar"
,
"barpath"
,
"barlocation"
,
"/bar-prefix"
,
true
,
Collections
.
EMPTY_SET
));
return
routes
;
}
...
...
@@ -73,6 +74,16 @@ public class RoutesEndpointTests {
}
@Test
public
void
testInvokeRouteDetails
()
{
RoutesEndpoint
endpoint
=
new
RoutesEndpoint
(
locator
);
Map
<
String
,
RoutesEndpoint
.
RouteDetails
>
results
=
new
HashMap
<>();
for
(
Route
route
:
locator
.
getRoutes
())
{
results
.
put
(
route
.
getFullPath
(),
new
RoutesEndpoint
.
RouteDetails
(
route
));
}
assertEquals
(
results
,
endpoint
.
invokeRouteDetails
());
}
@Test
public
void
testId
()
{
RoutesEndpoint
endpoint
=
new
RoutesEndpoint
(
locator
);
assertEquals
(
"routes"
,
endpoint
.
getId
());
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/RoutesMvcEndpointTests.java
View file @
ffc33b4c
...
...
@@ -42,6 +42,7 @@ import static org.mockito.Mockito.verify;
/**
* @author Ryan Baxter
* @author Gregor Zurowski
*/
@SpringBootTest
@RunWith
(
MockitoJUnitRunner
.
class
)
...
...
@@ -63,7 +64,7 @@ public class RoutesMvcEndpointTests {
public
List
<
Route
>
getRoutes
()
{
List
<
Route
>
routes
=
new
ArrayList
<>();
routes
.
add
(
new
Route
(
"foo"
,
"foopath"
,
"foolocation"
,
null
,
true
,
Collections
.
EMPTY_SET
));
routes
.
add
(
new
Route
(
"bar"
,
"barpath"
,
"barlocation"
,
null
,
true
,
Collections
.
EMPTY_SET
));
routes
.
add
(
new
Route
(
"bar"
,
"barpath"
,
"barlocation"
,
"bar-prefix"
,
true
,
Collections
.
EMPTY_SET
));
return
routes
;
}
...
...
@@ -88,4 +89,15 @@ public class RoutesMvcEndpointTests {
verify
(
publisher
,
times
(
1
)).
publishEvent
(
isA
(
RoutesRefreshedEvent
.
class
));
}
@Test
public
void
routeDetails
()
throws
Exception
{
RoutesMvcEndpoint
mvcEndpoint
=
new
RoutesMvcEndpoint
(
endpoint
,
locator
);
Map
<
String
,
RoutesEndpoint
.
RouteDetails
>
results
=
new
HashMap
<>();
for
(
Route
route
:
locator
.
getRoutes
())
{
results
.
put
(
route
.
getFullPath
(),
new
RoutesEndpoint
.
RouteDetails
(
route
));
}
assertEquals
(
results
,
mvcEndpoint
.
invokeRouteDetails
(
RoutesMvcEndpoint
.
FORMAT_DETAILS
));
verify
(
endpoint
,
times
(
1
)).
invokeRouteDetails
();
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment