harbor-master icon indicating copy to clipboard operation
harbor-master copied to clipboard

Query parameters aren't passed correctly to the Rest interface

Open polygonhell opened this issue 7 years ago • 5 comments

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}}}

polygonhell avatar Feb 22 '18 02:02 polygonhell

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.

markbirbeck avatar May 31 '18 10:05 markbirbeck

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.

lpeabody avatar Nov 19 '20 23:11 lpeabody

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.

lpeabody avatar Nov 19 '20 23:11 lpeabody

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.

markbirbeck avatar Jan 08 '21 19:01 markbirbeck

This looks excellent. Keen on trying this out in an upcoming project. Thanks @markbirbeck.

lpeabody avatar Jan 08 '21 20:01 lpeabody