Query parameters aren't passed correctly to the Rest interface
The docker docs are pretty bad for optional args to any of the commands but
To filter a service by name in the task API you need a request of the form
curl -v --unix-socket /var/run/docker.sock -X GET http:/v1.32/tasks?filters=%7B%22service%22%3A%7B%22service_name%22%3Atrue%7D%7D
The request library is restructuring the query part of the URI to something like
curl -v --unix-socket /var/run/docker.sock -X GET http:/v1.32/tasks?filters[service[service_name]]=true
I'm using the tasks endpoint with options of
{filters: {service: {"service_name": true}}}
I've come across the same problem. After juggling around with the code I've found that if I change the Joi definition for the tasks list command from Joi.object() to Joi.string() then I can do this:
const taskList = await client.tasks().list({filters: `{"service": {"${id}": true}}`});
and it all works.
I see that you don't have quotes around 'service' which didn't seem to work for me--the Docker API seems to require the quotes around each object property (i.e., proper JSON).
Although the API docs talk about the service name I found that I could use either the service name or the service ID and it works fine.
I could try and do a pull request but my suspicion is that this problem exists in other functions that take parameters, and I'm not sure I have enough knowledge of the Docker API to make the changes across other functions.
I can confirm this is a problem, and it is indeed due to the way the query string parameters are converted.
My example:
var options = {
filters: {
label: {
["com.docker.compose.project=" + COMPOSE_PROJECT_NAME]: true,
}
}
}
client.containers().list(options).then(list => {
console.log(list);
});
The above produces this in the engine log:
... msg="Calling GET /v1.32/containers/json?filters%5Blabel%5D%5Bcom.docker.compose.project%3Dgnorm-fed%5D=true&all=false&size=false"
The request library is fed the following options:
{
url: '/containers/json',
qs: { filters: { label: [Object] }, all: false, size: false },
method: 'GET'
}
To get the same information from the command line, we'd run docker container ls -f label=com.docker.compose.project=gnorm-fed -f label=com.docker.compose.service=cli
Which produces this in the engine logs:
... msg="Calling GET /v1.40/containers/json?filters=%7B%22label%22%3A%7B%22com.docker.compose.project%3Dgnorm-fed%22%3Atrue%2C%22com.docker.compose.service%3Dcli%22%3Atrue%7D%7D"
The key differences being that, when you compare each query string, you get filters%5B vs filters=. So, I don't think any usage of filters with this library currently works.
I believe @markbirbeck was on the right track by validating filters as a string rather than an object. The Docker engine API wants the filters parameter to be fed to it in a very particular way (e.g. url-encoded JSON string). However, the request library will take the required filters object and convert to have a URL-decoded value like:
Given:
{
filters: {
label: {
["com.docker.compose.project=" + COMPOSE_PROJECT_NAME]: true,
}
}
}
The request library converts filters in the query string like so:
filters[label][com.docker.compose.project=gnorm-fed]=true&all=false&size=false
I think a decent solution might be to do something like this at https://github.com/arhea/harbor-master/blob/master/lib/modem.js#L134
...
options.qs.filters = JSON.stringify(options.qs.filters)
console.log(options)
return request(options, cb);
...
Handling the filters query string value is a special use case, and since the request library can't handle it, the harbor-master library must.
EDIT: FYI making the above change, I get exactly my desired container listing.
I ended up writing my own with the following differences:
- I used the Docker Swagger files to go directly to the source definitions;
- I used ES6 proxies to allow the module to be used in place of other solutions;
- I added SSH tunnelling so that it could be used with AWS.
If it's of interest, see docker-engine.
This looks excellent. Keen on trying this out in an upcoming project. Thanks @markbirbeck.