Browse code

Merge pull request #36144 from emil2k/node-id-required

Produce errors when empty ids are passed into inspect calls.

Tõnis Tiigi authored on 2018/02/17 03:18:47
Showing 22 changed files
... ...
@@ -11,6 +11,9 @@ import (
11 11
 
12 12
 // ConfigInspectWithRaw returns the config information with raw data
13 13
 func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.Config, []byte, error) {
14
+	if id == "" {
15
+		return swarm.Config{}, nil, objectNotFoundError{object: "config", id: id}
16
+	}
14 17
 	if err := cli.NewVersionError("1.30", "config inspect"); err != nil {
15 18
 		return swarm.Config{}, nil, err
16 19
 	}
... ...
@@ -10,10 +10,34 @@ import (
10 10
 	"testing"
11 11
 
12 12
 	"github.com/docker/docker/api/types/swarm"
13
+	"github.com/pkg/errors"
13 14
 	"github.com/stretchr/testify/assert"
14 15
 	"golang.org/x/net/context"
15 16
 )
16 17
 
18
+func TestConfigInspectNotFound(t *testing.T) {
19
+	client := &Client{
20
+		client: newMockClient(errorMock(http.StatusNotFound, "Server error")),
21
+	}
22
+
23
+	_, _, err := client.ConfigInspectWithRaw(context.Background(), "unknown")
24
+	if err == nil || !IsErrNotFound(err) {
25
+		t.Fatalf("expected a NotFoundError error, got %v", err)
26
+	}
27
+}
28
+
29
+func TestConfigInspectWithEmptyID(t *testing.T) {
30
+	client := &Client{
31
+		client: newMockClient(func(req *http.Request) (*http.Response, error) {
32
+			return nil, errors.New("should not make request")
33
+		}),
34
+	}
35
+	_, _, err := client.ConfigInspectWithRaw(context.Background(), "")
36
+	if !IsErrNotFound(err) {
37
+		t.Fatalf("Expected NotFoundError, got %v", err)
38
+	}
39
+}
40
+
17 41
 func TestConfigInspectUnsupported(t *testing.T) {
18 42
 	client := &Client{
19 43
 		version: "1.29",
... ...
@@ -12,6 +12,9 @@ import (
12 12
 
13 13
 // ContainerInspect returns the container information.
14 14
 func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (types.ContainerJSON, error) {
15
+	if containerID == "" {
16
+		return types.ContainerJSON{}, objectNotFoundError{object: "container", id: containerID}
17
+	}
15 18
 	serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", nil, nil)
16 19
 	if err != nil {
17 20
 		return types.ContainerJSON{}, wrapResponseError(err, serverResp, "container", containerID)
... ...
@@ -25,6 +28,9 @@ func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (ty
25 25
 
26 26
 // ContainerInspectWithRaw returns the container information and its raw representation.
27 27
 func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID string, getSize bool) (types.ContainerJSON, []byte, error) {
28
+	if containerID == "" {
29
+		return types.ContainerJSON{}, nil, objectNotFoundError{object: "container", id: containerID}
30
+	}
28 31
 	query := url.Values{}
29 32
 	if getSize {
30 33
 		query.Set("size", "1")
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"testing"
11 11
 
12 12
 	"github.com/docker/docker/api/types"
13
+	"github.com/pkg/errors"
13 14
 	"golang.org/x/net/context"
14 15
 )
15 16
 
... ...
@@ -35,6 +36,18 @@ func TestContainerInspectContainerNotFound(t *testing.T) {
35 35
 	}
36 36
 }
37 37
 
38
+func TestContainerInspectWithEmptyID(t *testing.T) {
39
+	client := &Client{
40
+		client: newMockClient(func(req *http.Request) (*http.Response, error) {
41
+			return nil, errors.New("should not make request")
42
+		}),
43
+	}
44
+	_, _, err := client.ContainerInspectWithRaw(context.Background(), "", true)
45
+	if !IsErrNotFound(err) {
46
+		t.Fatalf("Expected NotFoundError, got %v", err)
47
+	}
48
+}
49
+
38 50
 func TestContainerInspect(t *testing.T) {
39 51
 	expectedURL := "/containers/container_id/json"
40 52
 	client := &Client{
... ...
@@ -12,6 +12,9 @@ import (
12 12
 func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegistryAuth string) (registrytypes.DistributionInspect, error) {
13 13
 	// Contact the registry to retrieve digest and platform information
14 14
 	var distributionInspect registrytypes.DistributionInspect
15
+	if image == "" {
16
+		return distributionInspect, objectNotFoundError{object: "distribution", id: image}
17
+	}
15 18
 
16 19
 	if err := cli.NewVersionError("1.30", "distribution inspect"); err != nil {
17 20
 		return distributionInspect, err
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"net/http"
5 5
 	"testing"
6 6
 
7
+	"github.com/pkg/errors"
7 8
 	"github.com/stretchr/testify/assert"
8 9
 	"golang.org/x/net/context"
9 10
 )
... ...
@@ -16,3 +17,15 @@ func TestDistributionInspectUnsupported(t *testing.T) {
16 16
 	_, err := client.DistributionInspect(context.Background(), "foobar:1.0", "")
17 17
 	assert.EqualError(t, err, `"distribution inspect" requires API version 1.30, but the Docker daemon API version is 1.29`)
18 18
 }
19
+
20
+func TestDistributionInspectWithEmptyID(t *testing.T) {
21
+	client := &Client{
22
+		client: newMockClient(func(req *http.Request) (*http.Response, error) {
23
+			return nil, errors.New("should not make request")
24
+		}),
25
+	}
26
+	_, err := client.DistributionInspect(context.Background(), "", "")
27
+	if !IsErrNotFound(err) {
28
+		t.Fatalf("Expected NotFoundError, got %v", err)
29
+	}
30
+}
... ...
@@ -11,6 +11,9 @@ import (
11 11
 
12 12
 // ImageInspectWithRaw returns the image information and its raw representation.
13 13
 func (cli *Client) ImageInspectWithRaw(ctx context.Context, imageID string) (types.ImageInspect, []byte, error) {
14
+	if imageID == "" {
15
+		return types.ImageInspect{}, nil, objectNotFoundError{object: "image", id: imageID}
16
+	}
14 17
 	serverResp, err := cli.get(ctx, "/images/"+imageID+"/json", nil, nil)
15 18
 	if err != nil {
16 19
 		return types.ImageInspect{}, nil, wrapResponseError(err, serverResp, "image", imageID)
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	"testing"
12 12
 
13 13
 	"github.com/docker/docker/api/types"
14
+	"github.com/pkg/errors"
14 15
 	"golang.org/x/net/context"
15 16
 )
16 17
 
... ...
@@ -36,6 +37,18 @@ func TestImageInspectImageNotFound(t *testing.T) {
36 36
 	}
37 37
 }
38 38
 
39
+func TestImageInspectWithEmptyID(t *testing.T) {
40
+	client := &Client{
41
+		client: newMockClient(func(req *http.Request) (*http.Response, error) {
42
+			return nil, errors.New("should not make request")
43
+		}),
44
+	}
45
+	_, _, err := client.ImageInspectWithRaw(context.Background(), "")
46
+	if !IsErrNotFound(err) {
47
+		t.Fatalf("Expected NotFoundError, got %v", err)
48
+	}
49
+}
50
+
39 51
 func TestImageInspect(t *testing.T) {
40 52
 	expectedURL := "/images/image_id/json"
41 53
 	expectedTags := []string{"tag1", "tag2"}
... ...
@@ -18,6 +18,9 @@ func (cli *Client) NetworkInspect(ctx context.Context, networkID string, options
18 18
 
19 19
 // NetworkInspectWithRaw returns the information for a specific network configured in the docker host and its raw representation.
20 20
 func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, options types.NetworkInspectOptions) (types.NetworkResource, []byte, error) {
21
+	if networkID == "" {
22
+		return types.NetworkResource{}, nil, objectNotFoundError{object: "network", id: networkID}
23
+	}
21 24
 	var (
22 25
 		networkResource types.NetworkResource
23 26
 		resp            serverResponse
... ...
@@ -11,6 +11,7 @@ import (
11 11
 
12 12
 	"github.com/docker/docker/api/types"
13 13
 	"github.com/docker/docker/api/types/network"
14
+	"github.com/pkg/errors"
14 15
 	"github.com/stretchr/testify/assert"
15 16
 	"golang.org/x/net/context"
16 17
 )
... ...
@@ -34,6 +35,18 @@ func TestNetworkInspectNotFoundError(t *testing.T) {
34 34
 	assert.True(t, IsErrNotFound(err))
35 35
 }
36 36
 
37
+func TestNetworkInspectWithEmptyID(t *testing.T) {
38
+	client := &Client{
39
+		client: newMockClient(func(req *http.Request) (*http.Response, error) {
40
+			return nil, errors.New("should not make request")
41
+		}),
42
+	}
43
+	_, _, err := client.NetworkInspectWithRaw(context.Background(), "", types.NetworkInspectOptions{})
44
+	if !IsErrNotFound(err) {
45
+		t.Fatalf("Expected NotFoundError, got %v", err)
46
+	}
47
+}
48
+
37 49
 func TestNetworkInspect(t *testing.T) {
38 50
 	expectedURL := "/networks/network_id"
39 51
 	client := &Client{
... ...
@@ -11,6 +11,9 @@ import (
11 11
 
12 12
 // NodeInspectWithRaw returns the node information.
13 13
 func (cli *Client) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error) {
14
+	if nodeID == "" {
15
+		return swarm.Node{}, nil, objectNotFoundError{object: "node", id: nodeID}
16
+	}
14 17
 	serverResp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil)
15 18
 	if err != nil {
16 19
 		return swarm.Node{}, nil, wrapResponseError(err, serverResp, "node", nodeID)
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"testing"
11 11
 
12 12
 	"github.com/docker/docker/api/types/swarm"
13
+	"github.com/pkg/errors"
13 14
 	"golang.org/x/net/context"
14 15
 )
15 16
 
... ...
@@ -35,6 +36,18 @@ func TestNodeInspectNodeNotFound(t *testing.T) {
35 35
 	}
36 36
 }
37 37
 
38
+func TestNodeInspectWithEmptyID(t *testing.T) {
39
+	client := &Client{
40
+		client: newMockClient(func(req *http.Request) (*http.Response, error) {
41
+			return nil, errors.New("should not make request")
42
+		}),
43
+	}
44
+	_, _, err := client.NodeInspectWithRaw(context.Background(), "")
45
+	if !IsErrNotFound(err) {
46
+		t.Fatalf("Expected NotFoundError, got %v", err)
47
+	}
48
+}
49
+
38 50
 func TestNodeInspect(t *testing.T) {
39 51
 	expectedURL := "/nodes/node_id"
40 52
 	client := &Client{
... ...
@@ -11,6 +11,9 @@ import (
11 11
 
12 12
 // PluginInspectWithRaw inspects an existing plugin
13 13
 func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) {
14
+	if name == "" {
15
+		return nil, nil, objectNotFoundError{object: "plugin", id: name}
16
+	}
14 17
 	resp, err := cli.get(ctx, "/plugins/"+name+"/json", nil, nil)
15 18
 	if err != nil {
16 19
 		return nil, nil, wrapResponseError(err, resp, "plugin", name)
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"testing"
11 11
 
12 12
 	"github.com/docker/docker/api/types"
13
+	"github.com/pkg/errors"
13 14
 	"golang.org/x/net/context"
14 15
 )
15 16
 
... ...
@@ -24,6 +25,18 @@ func TestPluginInspectError(t *testing.T) {
24 24
 	}
25 25
 }
26 26
 
27
+func TestPluginInspectWithEmptyID(t *testing.T) {
28
+	client := &Client{
29
+		client: newMockClient(func(req *http.Request) (*http.Response, error) {
30
+			return nil, errors.New("should not make request")
31
+		}),
32
+	}
33
+	_, _, err := client.PluginInspectWithRaw(context.Background(), "")
34
+	if !IsErrNotFound(err) {
35
+		t.Fatalf("Expected NotFoundError, got %v", err)
36
+	}
37
+}
38
+
27 39
 func TestPluginInspect(t *testing.T) {
28 40
 	expectedURL := "/plugins/plugin_name"
29 41
 	client := &Client{
... ...
@@ -14,6 +14,9 @@ func (cli *Client) SecretInspectWithRaw(ctx context.Context, id string) (swarm.S
14 14
 	if err := cli.NewVersionError("1.25", "secret inspect"); err != nil {
15 15
 		return swarm.Secret{}, nil, err
16 16
 	}
17
+	if id == "" {
18
+		return swarm.Secret{}, nil, objectNotFoundError{object: "secret", id: id}
19
+	}
17 20
 	resp, err := cli.get(ctx, "/secrets/"+id, nil, nil)
18 21
 	if err != nil {
19 22
 		return swarm.Secret{}, nil, wrapResponseError(err, resp, "secret", id)
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"testing"
11 11
 
12 12
 	"github.com/docker/docker/api/types/swarm"
13
+	"github.com/pkg/errors"
13 14
 	"github.com/stretchr/testify/assert"
14 15
 	"golang.org/x/net/context"
15 16
 )
... ...
@@ -47,6 +48,18 @@ func TestSecretInspectSecretNotFound(t *testing.T) {
47 47
 	}
48 48
 }
49 49
 
50
+func TestSecretInspectWithEmptyID(t *testing.T) {
51
+	client := &Client{
52
+		client: newMockClient(func(req *http.Request) (*http.Response, error) {
53
+			return nil, errors.New("should not make request")
54
+		}),
55
+	}
56
+	_, _, err := client.SecretInspectWithRaw(context.Background(), "")
57
+	if !IsErrNotFound(err) {
58
+		t.Fatalf("Expected NotFoundError, got %v", err)
59
+	}
60
+}
61
+
50 62
 func TestSecretInspect(t *testing.T) {
51 63
 	expectedURL := "/v1.25/secrets/secret_id"
52 64
 	client := &Client{
... ...
@@ -14,6 +14,9 @@ import (
14 14
 
15 15
 // ServiceInspectWithRaw returns the service information and the raw data.
16 16
 func (cli *Client) ServiceInspectWithRaw(ctx context.Context, serviceID string, opts types.ServiceInspectOptions) (swarm.Service, []byte, error) {
17
+	if serviceID == "" {
18
+		return swarm.Service{}, nil, objectNotFoundError{object: "service", id: serviceID}
19
+	}
17 20
 	query := url.Values{}
18 21
 	query.Set("insertDefaults", fmt.Sprintf("%v", opts.InsertDefaults))
19 22
 	serverResp, err := cli.get(ctx, "/services/"+serviceID, query, nil)
... ...
@@ -11,6 +11,7 @@ import (
11 11
 
12 12
 	"github.com/docker/docker/api/types"
13 13
 	"github.com/docker/docker/api/types/swarm"
14
+	"github.com/pkg/errors"
14 15
 	"golang.org/x/net/context"
15 16
 )
16 17
 
... ...
@@ -36,6 +37,18 @@ func TestServiceInspectServiceNotFound(t *testing.T) {
36 36
 	}
37 37
 }
38 38
 
39
+func TestServiceInspectWithEmptyID(t *testing.T) {
40
+	client := &Client{
41
+		client: newMockClient(func(req *http.Request) (*http.Response, error) {
42
+			return nil, errors.New("should not make request")
43
+		}),
44
+	}
45
+	_, _, err := client.ServiceInspectWithRaw(context.Background(), "", types.ServiceInspectOptions{})
46
+	if !IsErrNotFound(err) {
47
+		t.Fatalf("Expected NotFoundError, got %v", err)
48
+	}
49
+}
50
+
39 51
 func TestServiceInspect(t *testing.T) {
40 52
 	expectedURL := "/services/service_id"
41 53
 	client := &Client{
... ...
@@ -11,6 +11,9 @@ import (
11 11
 
12 12
 // TaskInspectWithRaw returns the task information and its raw representation..
13 13
 func (cli *Client) TaskInspectWithRaw(ctx context.Context, taskID string) (swarm.Task, []byte, error) {
14
+	if taskID == "" {
15
+		return swarm.Task{}, nil, objectNotFoundError{object: "task", id: taskID}
16
+	}
14 17
 	serverResp, err := cli.get(ctx, "/tasks/"+taskID, nil, nil)
15 18
 	if err != nil {
16 19
 		return swarm.Task{}, nil, wrapResponseError(err, serverResp, "task", taskID)
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"testing"
11 11
 
12 12
 	"github.com/docker/docker/api/types/swarm"
13
+	"github.com/pkg/errors"
13 14
 	"golang.org/x/net/context"
14 15
 )
15 16
 
... ...
@@ -24,6 +25,18 @@ func TestTaskInspectError(t *testing.T) {
24 24
 	}
25 25
 }
26 26
 
27
+func TestTaskInspectWithEmptyID(t *testing.T) {
28
+	client := &Client{
29
+		client: newMockClient(func(req *http.Request) (*http.Response, error) {
30
+			return nil, errors.New("should not make request")
31
+		}),
32
+	}
33
+	_, _, err := client.TaskInspectWithRaw(context.Background(), "")
34
+	if !IsErrNotFound(err) {
35
+		t.Fatalf("Expected NotFoundError, got %v", err)
36
+	}
37
+}
38
+
27 39
 func TestTaskInspect(t *testing.T) {
28 40
 	expectedURL := "/tasks/task_id"
29 41
 	client := &Client{
... ...
@@ -4,7 +4,6 @@ import (
4 4
 	"bytes"
5 5
 	"encoding/json"
6 6
 	"io/ioutil"
7
-	"path"
8 7
 
9 8
 	"github.com/docker/docker/api/types"
10 9
 	"golang.org/x/net/context"
... ...
@@ -18,15 +17,12 @@ func (cli *Client) VolumeInspect(ctx context.Context, volumeID string) (types.Vo
18 18
 
19 19
 // VolumeInspectWithRaw returns the information about a specific volume in the docker host and its raw representation
20 20
 func (cli *Client) VolumeInspectWithRaw(ctx context.Context, volumeID string) (types.Volume, []byte, error) {
21
-	// The empty ID needs to be handled here because with an empty ID the
22
-	// request url will not contain a trailing / which calls the volume list API
23
-	// instead of volume inspect
24 21
 	if volumeID == "" {
25 22
 		return types.Volume{}, nil, objectNotFoundError{object: "volume", id: volumeID}
26 23
 	}
27 24
 
28 25
 	var volume types.Volume
29
-	resp, err := cli.get(ctx, path.Join("/volumes", volumeID), nil, nil)
26
+	resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil)
30 27
 	if err != nil {
31 28
 		return volume, nil, wrapResponseError(err, resp, "volume", volumeID)
32 29
 	}
... ...
@@ -11,6 +11,7 @@ import (
11 11
 
12 12
 	"github.com/docker/docker/api/types"
13 13
 	"github.com/docker/docker/internal/testutil"
14
+	"github.com/pkg/errors"
14 15
 	"github.com/stretchr/testify/assert"
15 16
 	"github.com/stretchr/testify/require"
16 17
 	"golang.org/x/net/context"
... ...
@@ -35,20 +36,15 @@ func TestVolumeInspectNotFound(t *testing.T) {
35 35
 }
36 36
 
37 37
 func TestVolumeInspectWithEmptyID(t *testing.T) {
38
-	expectedURL := "/volumes/"
39
-
40 38
 	client := &Client{
41 39
 		client: newMockClient(func(req *http.Request) (*http.Response, error) {
42
-			assert.Equal(t, req.URL.Path, expectedURL)
43
-			return &http.Response{
44
-				StatusCode: http.StatusNotFound,
45
-				Body:       ioutil.NopCloser(bytes.NewReader(nil)),
46
-			}, nil
40
+			return nil, errors.New("should not make request")
47 41
 		}),
48 42
 	}
49
-	_, err := client.VolumeInspect(context.Background(), "")
50
-	testutil.ErrorContains(t, err, "No such volume: ")
51
-
43
+	_, _, err := client.VolumeInspectWithRaw(context.Background(), "")
44
+	if !IsErrNotFound(err) {
45
+		t.Fatalf("Expected NotFoundError, got %v", err)
46
+	}
52 47
 }
53 48
 
54 49
 func TestVolumeInspect(t *testing.T) {