daemon: Daemon.getNetworkedContainer: fix errors for invalid network container

When failing to resolve the network container, a "not found" error should
not return a 404, but either a "invalid parameter" (400) or "system" (500)
error.

Given that this function is called on container start, not container create,
a 500 (internal server error) is more appropriate, because the API request
(start the container) is valid, but the state of the container isn't.

While working on this, I discovered that no validation happens during container
create; TODO's were added to look into that, but this may be partially
by design (allow a container to be created before the "donor" network
container is created).

Before this patch:

    docker container create --name hello --network=container:nosuchcontainer alpine
    docker container start hello
    Error response from daemon: No such container: nosuchcontainer
    Error: failed to start containers: hello

    # daemon logs:
    DEBU[2025-01-30T11:32:33.595636043Z] error response for POST request               error-response="No such container: nosuchcontainer" method=POST module=api request-url=/v1.47/containers/hello/start status=404 vars="map[name:hello version:1.47]"

    docker container create --name hello2 --network=container:hello2 alpine
    docker container start hello2
    Error response from daemon: cannot join own network
    Error: failed to start containers: hello2

    # daemon logs:
    DEBU[2025-01-30T11:33:19.545287551Z] FIXME: Got an API for which error does not match any expected type!!!  error="cannot join own network" error_type="*errors.errorString" module=api
    DEBU[2025-01-30T11:33:19.545346093Z] error response for POST request               error-response="cannot join own network" method=POST module=api request-url=/v1.47/containers/hello2/start status=500 vars="map[name:hello2 version:1.47]"
    DEBU[2025-01-30T11:33:19.545369968Z] FIXME: Got an API for which error does not match any expected type!!!  error="cannot join own network" error_type="*errors.errorString" module=api
    ERRO[2025-01-30T11:33:19.545375426Z] Handler for POST /v1.47/containers/hello2/start returned error: cannot join own network

With this patch:

    docker container create --name hello --network=container:nosuchcontainer alpine
    docker container start hello
    Error response from daemon: joining network of container: No such container: nosuchcontainer
    Error: failed to start containers: hello

    # daemon logs:
    DEBU[2025-01-30T11:35:50.406462760Z] error response for POST request               error-response="joining network of container: No such container: nosuchcontainer" method=POST module=api request-url=/v1.47/containers/hello/start status=500 vars="map[name:hello version:1.47]"
    ERRO[2025-01-30T11:35:50.406501468Z] Handler for POST /v1.47/containers/hello/start returned error: joining network of container: No such container: nosuchcontainer

    docker container create --name hello2 --network=container:hello2 alpine
    docker container start hello2
    Error response from daemon: cannot join own network namespace
    Error: failed to start containers: hello2

    # daemon logs:
    DEBU[2025-01-30T11:36:15.178475049Z] error response for POST request               error-response="cannot join own network" method=POST module=api request-url=/v1.47/containers/hello2/start status=500 vars="map[name:hello2 version:1.47]"
    ERRO[2025-01-30T11:36:15.178536507Z] Handler for POST /v1.47/containers/hello2/start returned error: cannot join own network

    docker run --name exitedcontainer alpine
    docker run --rm --network=container:exitedcontainer alpine
    docker: Error response from daemon: cannot join network namespace of a non running container: container exitedcontainer is exited.

    # daemon logs:
    DEBU[2025-01-30T12:54:28.040637429Z] error response for POST request               error-response="cannot join network namespace of a non running container: container exitedcontainer is exited" method=POST module=api request-url=/v1.47/containers/hello2/start status=409 vars="map[name:hello2 version:1.47]"

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2025-01-30 13:59:40 +01:00
parent c42005e944
commit 513fd86710

View File

@@ -901,19 +901,37 @@ func (daemon *Daemon) normalizeNetMode(ctr *container.Container) error {
return nil
}
func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID string) (*container.Container, error) {
nc, err := daemon.GetContainer(connectedContainerID)
func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerPrefixOrName string) (*container.Container, error) {
nc, err := daemon.GetContainer(connectedContainerPrefixOrName)
if err != nil {
err = fmt.Errorf("joining network namespace of container: %w", err)
if errdefs.IsNotFound(err) {
// Deliberately masking "not found" errors, because failing to find
// the network container is a system error. We return a system error,
// not an "invalid parameter" because getNetworkedContainer is called
// during container start, not container "create"; we assume the container
// did resolve successfully when creating the container.
//
// FIXME (thaJeztah): turns out we don't validate "--network container:<missing container>" during container create!
// ^^ this may have been by design to allow the container to be created before the "donor" container is
// created, so this must be looked into.
return nil, errdefs.System(err)
}
return nil, err
}
if containerID == nc.ID {
return nil, fmt.Errorf("cannot join own network")
// We return a system error, not an "invalid parameter" because getNetworkedContainer is called
// during container start, not container "create"; we assume the networked container did resolve
// successfully when creating the container, and was validated during container create.
//
// FIXME (thaJeztah): turns out we don't validate "--network container:<self>" during container create!
return nil, errdefs.System(errdefs.InvalidParameter(errors.New("cannot join own network namespace")))
}
if !nc.IsRunning() {
return nil, errdefs.Conflict(fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID))
return nil, errdefs.Conflict(fmt.Errorf("cannot join network namespace of a non running container: container %s is %s", strings.TrimPrefix(nc.Name, "/"), nc.StateString()))
}
if nc.IsRestarting() {
return nil, errContainerIsRestarting(connectedContainerID)
return nil, fmt.Errorf("cannot join network namespace of container: %w", errContainerIsRestarting(connectedContainerPrefixOrName))
}
return nc, nil
}