Browse code

Return "invalid parameter" when linking to non-existing container

Trying to link to a non-existing container is not valid, and should return an
"invalid parameter" (400) error. Returning a "not found" error in this situation
would make the client report the container's image could not be found.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2019/09/03 06:39:24
Showing 2 changed files
... ...
@@ -24,6 +24,7 @@ import (
24 24
 	"github.com/docker/docker/container"
25 25
 	"github.com/docker/docker/daemon/config"
26 26
 	"github.com/docker/docker/daemon/initlayer"
27
+	"github.com/docker/docker/errdefs"
27 28
 	"github.com/docker/docker/opts"
28 29
 	"github.com/docker/docker/pkg/containerfs"
29 30
 	"github.com/docker/docker/pkg/idtools"
... ...
@@ -1324,12 +1325,26 @@ func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *
1324 1324
 		}
1325 1325
 		child, err := daemon.GetContainer(name)
1326 1326
 		if err != nil {
1327
+			if errdefs.IsNotFound(err) {
1328
+				// Trying to link to a non-existing container is not valid, and
1329
+				// should return an "invalid parameter" error. Returning a "not
1330
+				// found" error here would make the client report the container's
1331
+				// image could not be found (see moby/moby#39823)
1332
+				err = errdefs.InvalidParameter(err)
1333
+			}
1327 1334
 			return errors.Wrapf(err, "could not get container for %s", name)
1328 1335
 		}
1329 1336
 		for child.HostConfig.NetworkMode.IsContainer() {
1330 1337
 			parts := strings.SplitN(string(child.HostConfig.NetworkMode), ":", 2)
1331 1338
 			child, err = daemon.GetContainer(parts[1])
1332 1339
 			if err != nil {
1340
+				if errdefs.IsNotFound(err) {
1341
+					// Trying to link to a non-existing container is not valid, and
1342
+					// should return an "invalid parameter" error. Returning a "not
1343
+					// found" error here would make the client report the container's
1344
+					// image could not be found (see moby/moby#39823)
1345
+					err = errdefs.InvalidParameter(err)
1346
+				}
1333 1347
 				return errors.Wrapf(err, "Could not get container for %s", parts[1])
1334 1348
 			}
1335 1349
 		}
... ...
@@ -65,6 +65,28 @@ func TestCreateFailsWhenIdentifierDoesNotExist(t *testing.T) {
65 65
 	}
66 66
 }
67 67
 
68
+// TestCreateLinkToNonExistingContainer verifies that linking to a non-existing
69
+// container returns an "invalid parameter" (400) status, and not the underlying
70
+// "non exists" (404).
71
+func TestCreateLinkToNonExistingContainer(t *testing.T) {
72
+	skip.If(t, testEnv.DaemonInfo.OSType == "windows", "legacy links are not supported on windows")
73
+	defer setupTest(t)()
74
+	c := testEnv.APIClient()
75
+
76
+	_, err := c.ContainerCreate(context.Background(),
77
+		&container.Config{
78
+			Image: "busybox",
79
+		},
80
+		&container.HostConfig{
81
+			Links: []string{"no-such-container"},
82
+		},
83
+		&network.NetworkingConfig{},
84
+		"",
85
+	)
86
+	assert.Check(t, is.ErrorContains(err, "could not get container for no-such-container"))
87
+	assert.Check(t, errdefs.IsInvalidParameter(err))
88
+}
89
+
68 90
 func TestCreateWithInvalidEnv(t *testing.T) {
69 91
 	defer setupTest(t)()
70 92
 	client := testEnv.APIClient()