Skip to content

Produce errors when empty ids are passed into inspect calls. #36144

Merged
tonistiigi merged 1 commit intomoby:masterfrom
emil2k:node-id-required
Feb 16, 2018
Merged

Produce errors when empty ids are passed into inspect calls. #36144
tonistiigi merged 1 commit intomoby:masterfrom
emil2k:node-id-required

Conversation

@emil2k
Copy link
Copy Markdown
Contributor

@emil2k emil2k commented Jan 30, 2018

- What I did

Made the client validate when empty IDs are passed into inspect methods to prevent calling the wrong endpoint and returning the wrong error.

Previously, if for example a blank nodeID was passed in to NodeInspectWithRaw the result was a node list request. The response would then fail to unmarshal into a Node type returning a JSON error.

- How I did it

Checked ids passed into inspect calls and returned an error if they were empty.

- How to verify it

Test added.

- Description for the changelog
Produce errors when empty ids are passed into inspect calls.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is needed. Other object types don't have this check (e.g.

// ServiceInspectWithRaw returns the service information and the raw data.
func (cli *Client) ServiceInspectWithRaw(ctx context.Context, serviceID string, opts types.ServiceInspectOptions) (swarm.Service, []byte, error) {
query := url.Values{}
query.Set("insertDefaults", fmt.Sprintf("%v", opts.InsertDefaults))
serverResp, err := cli.get(ctx, "/services/"+serviceID, query, nil)
if err != nil {
return swarm.Service{}, nil, wrapResponseError(err, serverResp, "service", serviceID)
}
defer ensureReaderClosed(serverResp)
body, err := ioutil.ReadAll(serverResp.body)
if err != nil {
return swarm.Service{}, nil, err
}
var response swarm.Service
rdr := bytes.NewReader(body)
err = json.NewDecoder(rdr).Decode(&response)
return response, body, err
}
)

There's already validation in place on the CLI;

$ docker node inspect
"docker node inspect" requires at least 1 argument.

And the API server performs additional validation;

$ curl --unix-socket /var/run/docker.sock http://localhost/nodes/ 
{"message":"page not found"}

Not entirely against, but I want to guard against having validation in the client where it's not needed, and try to keep as much as possible on the daemon side

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately I think this is necessary. I added a similar check for volumes in #34770.

The problem is in building the url. If the arg is blank, the url path ends up being /nodes, which is a valid URL (https://docs.docker.com/engine/api/v1.30/#operation/NodeList). I'm not sure why that curl failed.

I wish there was a better way of handling this, but I haven't found anything yet.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Difference is in the trailing /; without a trailing /, it's "list nodes", and with a trailing /, it's "view/inspect node"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right! So I guess the line below this should be using path.Join() to construct the url

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Difference is in the trailing /; without a trailing /, it's "list nodes", and with a trailing /, it's "view/inspect node"

@thaJeztah My client was making a request for nodes/ with the trailing /, but was receiving the results from the list nodes endpoint, so maybe there is an issue with the routing.

I found a go-swagger issue that seems to have removed any meaning associated with a trailing slash explaining this behavior:
go-swagger/go-swagger#906
go-swagger/go-swagger#899 (comment)

This could have affected your API server's routing. You might not be seeing this on your local setup because your Makefile is using an old version of go-swagger:

.PHONY: swagger-gen
swagger-gen:
	docker run --rm -v $(PWD):/go/src/github.com/docker/docker \
		-w /go/src/github.com/docker/docker \
		--entrypoint hack/generate-swagger-api.sh \
		-e GOPATH=/go \
		quay.io/goswagger/swagger:0.7.4

While the commit that made these changes was added in version 9.0 of go-swagger:
go-swagger/go-swagger@5ef60f1

Meanwhile, the commit being used in the Dockerfile to build Docker is using a commit that points to version 0.13 of go-wrapper:

# Install go-swagger for validating swagger.yaml
ENV GO_SWAGGER_COMMIT c28258affb0b6251755d92489ef685af8d4ff3eb
RUN git clone https://github.com/go-swagger/go-swagger.git /go/src/github.com/go-swagger/go-swagger \
	&& (cd /go/src/github.com/go-swagger/go-swagger && git checkout -q $GO_SWAGGER_COMMIT) \
	&& go install -v github.com/go-swagger/go-swagger/cmd/swagger

go-swagger/go-swagger@c28258a

Here are my client/server versions:

Client:
 Version:      17.11.0-ce
 API version:  1.30 (downgraded from 1.34)
 Go version:   go1.9.2
 Git commit:   1caf76c
 Built:        unknown-buildtime
 OS/Arch:      darwin/amd64

Server:
 Version:      17.06.2-ce
 API version:  1.30 (minimum version 1.12)
 Go version:   go1.8.4
 Git commit:   402dd4a/17.06.2-ce
 Built:        Fri Nov 10 00:51:08 2017
 OS/Arch:      linux/amd64
 Experimental: false

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be consistent here, how about an error like this: https://github.com/moby/moby/pull/34770/files#diff-18fbe225ba23b481ee707e859ff03b0cR22

and a test case

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the error to be consistent with the volume inspect call and added a similar test case.

@emil2k
Copy link
Copy Markdown
Contributor Author

emil2k commented Feb 5, 2018

I think maybe this comment got lost, because it was in a discussion on an old diff:
#36144 (comment)

I'm referring to it here because I think it is relevant to the issue at hand.

@thaJeztah
Copy link
Copy Markdown
Member

Thanks @emil2k - regarding the trailing slash; this was the PR I had in mind; #24634. I recall a discussion somewhere where it was suggested that having a trailing slash (or not) should route to a different endpoint (but I wasn't really in favour of that). Perhaps it's worth to verify the behaviour of relevant endpoints.

For this change: I discussed this with @dnephin (I thought I left a comment, but apparently forgot 😅), and we agreed that having a validation for empty values in the client does make sense.

If we make this change, I'd prefer it to be done for all similar endpoints (i.e. all endpoints that expect an ID should produce an error indicating that the ID was empty - if it's not currently handled like that)

If a blank nodeID was previously passed in it resulted in a node list
request. The response would then fail to umarshal into a `Node`
type returning a JSON error.

This adds an extra validation to all inspect calls to check that the ID
that is required is provided and if not return an error.

Signed-off-by: Emil Davtyan <emil2k@gmail.com>
@emil2k emil2k changed the title Produce "node id is required" error. Produce errors when empty ids are passed into inspect calls. Feb 7, 2018
@emil2k
Copy link
Copy Markdown
Contributor Author

emil2k commented Feb 7, 2018

@thaJeztah I added this check and tests to all the inspect calls.

Copy link
Copy Markdown
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@dnephin PTAL


var volume types.Volume
resp, err := cli.get(ctx, path.Join("/volumes", volumeID), nil, nil)
resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change? I think using path.Join() is correct

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we use concatenation in all the other endpoints

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to be consistent with the other similar methods. Also for simplicity, I could not see a case where it would be necessary to use path.Join over the simple concat, but I maybe overlooking something.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the only case where it would be different is the empty string value. I guess it's fine, we can fix them all at once at some later time.

Copy link
Copy Markdown
Member

@dnephin dnephin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@tonistiigi tonistiigi merged commit db36099 into moby:master Feb 16, 2018
@emil2k emil2k deleted the node-id-required branch February 16, 2018 20:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants