[wildfly-dev] Steamable content in management API responses

Brian Stansberry brian.stansberry at redhat.com
Wed Oct 1 10:52:57 EDT 2014


tl;dr

I'm looking into supported streamed content in management API responses 
and wanted to get feedback.

The admin console has a need for a streamed response, as we have a 
requirement to let a user download a log file to store on local disk. 
The browser can itself directly download a file using HTTP, but will not 
let an app like the console make multiple DMR requests and itself append 
data from the responses to a file on disk.

There are other likely uses cases for a similar thing, e.g. reading the 
contents of the content (aka deployment) repository.

We already support attaching streams to requests; the proposal is to do 
much the same with responses. For HTTP clients, if a request is for 
something that attaches a stream to the response, the request URL can 
include a query param instructing the server to pipe the stream for the 
response instead of sending the standard JSON reponse value.

Long version:


Requirements:

1) Ability to send arbitrarily long amounts of data in management responses.

Currently everything in a management response has to be encodable in 
DMR. DMR will allow you to send a byte[] as a response value, but for 
memory reasons this isn't a practical approach for large responses.

2) Ability to send the data directly to an HTTP request, not wrapped in 
a JSON wrapper. Even if we would include a huge value as a JSON encoded 
byte[], a browser won't let an app like the console read those bytes out 
of the JSON response and write them to disk. A direct response to an 
HTTP GET/POST is needed.

3) Works for other remoting-based clients as well. This is a basic 
requirement that HTTP and remoting-based clients can each do everything. 
So, no HTTP only side features.

4) Requests go through the central management layer, so we have proper 
security, audit logging etc. So, no special endpoints that bypass the 
core management layer.

Proposal:

We already support attaching a stream to the request for native clients. 
(This is how the CLI does deployments.) The client API lets the client 
associate a stream with the request[1]. The stream has an index. The 
operation that needs the stream takes a DMR param that tells it the 
index of the stream. On the server side the handler uses that param 
value to find the server-side representation of the stream. The remoting 
layer of the remote management protocol in the background handles piping 
the contents of the client side stream to the server.

The proposal is to simply mirror this in reverse. A server side 
operation handler associates a stream with the response (via a call on 
the OperationContext). The attached stream has an index. The normal DMR 
response to the operation is the index of the stream. The client uses 
that response value to find the attached stream. The remoting layer of 
the remote management protocol in the background handles piping the 
contents of the server side stream to the client.

This handles remoting based clients, including those using http upgrade.

For HTTP clients, the client can include a "useStreamAsResponse" query 
param in the request URL. If this is present, the server side endpoint 
will take the stream from the internal response and pipe it to the 
client, instead of sending the normal JSON.

For example, a fictitious URL for a "stream-log-file" op against a 
resource that represents the server.log file:

http://localhost:9090/management/subsystem/logging/log-file/server.log?operation=stream-log-file&useStreamAsResponse

In the corner case where a request results in more than one attached 
response, the useStreamAsResponse could include an index.

useStreamAsResponse=1

Status:

It was reasonably straightforward to get this working, as a fairly 
polished prototype:

https://github.com/bstansberry/wildfly-core/commits/resp-stream

The 2nd commit there just hacks in an attribute to the logging subsystem 
root resource to expose the server log as a stream. There's no intent to 
actually do it that specific way of course; it was just an easy way to 
demonstrate.

With that built an HTTP GET will download the log file to your desktop.

http://localhost:9990/management/subsystem/logging?operation=attribute&name=server-log&useStreamAsResponse

The native interface works as well. The 2nd commit includes a test case 
that confirms this. So the CLI  easily enough could add a high level 
command for log reading too.

TODOs:

1) Domain mode: proxy the streams around the domain 
(server->HC->DC->client). I think this should be quite easy.

2) A cleaner variant of the remoting-based management protocol for 
handling the streams, one that doesn't require hacks to determine the 
length of the stream in advance. Should be relatively straightforward.

3) Logic to clean up server side streams if the client doesn't properly 
consume them.

4) Make sure there a no issues with the thread pools used to handle 
management requests.

5) Make sure POST works well. My assumption is this is lower priority, 
as the real use cases would likely use a GET.


[1] 
https://github.com/wildfly/wildfly-core/blob/master/controller-client/src/main/java/org/jboss/as/controller/client/OperationBuilder.java

-- 
Brian Stansberry
Senior Principal Software Engineer
JBoss by Red Hat


More information about the wildfly-dev mailing list