Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query parameters aren't passed correctly to the Rest interface #6

Open
polygonhell opened this issue Feb 22, 2018 · 5 comments
Open

Comments

@polygonhell
Copy link

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

@markbirbeck
Copy link

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.

@lpeabody
Copy link

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
Copy link

lpeabody commented Nov 19, 2020

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.

@markbirbeck
Copy link

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.

@lpeabody
Copy link

lpeabody commented Jan 8, 2021

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants