The stringid package is used in many places; while it's trivial
to implement a similar utility, let's just provide it as a utility
package in the client, removing the daemon-specific logic.
For integration tests, I opted to use the implementation in the
client, as those should not ideally not make assumptions about
the daemon implementation.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
These comments were added to enforce using the correct import path for
our packages ("github.com/docker/docker", not "github.com/moby/moby").
However, when working in go module mode (not GOPATH / vendor), they have
no effect, so their impact is limited.
Remove these imports in preparation of migrating our code to become an
actual go module.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This patch fixes a bug in the daemon's restore step on startup, where
a container with a name matching another container's ID would not be
restored.
`Daemon.registerName` is used during startup as part of the daemon's
container restore code
97b1233a15/daemon/daemon.go (L331-L344)
In that process, it first registers the containers names through
[`Daemon.registerName()`][1], then registers the container's ID through
[`Daemon.Register()`][1], which calls `Daemon.containers.Add()` under the
hood.
Restoring containers is done in a goroutine, and at this stage of the daemon's
lifecycle, not all containers may be restored yet. However, `Daemon.registerName()`
has some safeguard to prevent the same container from being restored _twice_
through [`Daemon.Exists()`][3]. If a duplicate is found, an error is logged, and
the container is not restored (but kept on disk).
While it's disputable if this logic is needed at all, perhaps a panic would be
more appropriate (duplicate containers were stored on disk), there's also a
flaw in the current implementation of this check.
The [`Daemon.Exists()`][3] function uses [`Daemon.GetContainer()`][4] to look
up the container. This function performs fuzzy matching on the given reference,
first trying to match containers on their full ID, which _should_ not give a
match at this stage, before falling back to matching containers by name and
partial prefix.
This last part can be problematic in situations where a container exists that
uses the container to restore's ID as name. In such cases, the container will
be considered "already present", and not restored.
Create a container, then create a number of containers, each of which using
the ID of the previous container as name.
docker create --name one hello-world
d54301b7560f3c3544acc2d9c9dd55a194d6db37c2af64fe83fa34238c7ce6ab
docker create --name d54301b7560f3c3544acc2d9c9dd55a194d6db37c2af64fe83fa34238c7ce6ab hello-world
217c53b9826eb7875ca2620596864d039848470befeb5f963b3ebffe509e7a6d
docker create --name 217c53b9826eb7875ca2620596864d039848470befeb5f963b3ebffe509e7a6d hello-world
b125af485d6d1875b586b314f93af1b49d5baaa94cec4199ae4ef4c6da05e7e4
docker create --name b125af485d6d1875b586b314f93af1b49d5baaa94cec4199ae4ef4c6da05e7e4 hello-world
The daemon should now have a number of containers where the ID and name
conflict:
docker ps -a --no-trunc --format 'table {{.ID}}\t{{.Names}}'
CONTAINER ID NAMES
f59e8e4044471c45d4c9841d11a2c586cbfa4703b1344035fd51a15e15899ea7 b125af485d6d1875b586b314f93af1b49d5baaa94cec4199ae4ef4c6da05e7e4
b125af485d6d1875b586b314f93af1b49d5baaa94cec4199ae4ef4c6da05e7e4 217c53b9826eb7875ca2620596864d039848470befeb5f963b3ebffe509e7a6d
217c53b9826eb7875ca2620596864d039848470befeb5f963b3ebffe509e7a6d d54301b7560f3c3544acc2d9c9dd55a194d6db37c2af64fe83fa34238c7ce6ab
d54301b7560f3c3544acc2d9c9dd55a194d6db37c2af64fe83fa34238c7ce6ab one
Restart the daemon. Depending on the order in which containers are restored,
a conflict may happen, and the conflicting container will not be restored.
Logs below are from the daemon with debug enabled;
INFO[2024-10-15T11:13:38.770744797Z] Loading containers: start.
DEBU[2024-10-15T11:13:38.771152214Z] processing event stream module=libcontainerd namespace=moby
DEBU[2024-10-15T11:13:38.771599797Z] loaded container container=d54301b7560f3c3544acc2d9c9dd55a194d6db37c2af64fe83fa34238c7ce6ab paused=false running=false
DEBU[2024-10-15T11:13:38.771637464Z] loaded container container=217c53b9826eb7875ca2620596864d039848470befeb5f963b3ebffe509e7a6d paused=false running=false
DEBU[2024-10-15T11:13:38.771672714Z] loaded container container=bbe03a6554867810c2d7464ed3cb853865c755bae797b8d1f4caf60fb3f9fa04 paused=false running=false
DEBU[2024-10-15T11:13:38.771765297Z] loaded container container=f59e8e4044471c45d4c9841d11a2c586cbfa4703b1344035fd51a15e15899ea7 paused=false running=false
DEBU[2024-10-15T11:13:38.771780839Z] loaded container container=b125af485d6d1875b586b314f93af1b49d5baaa94cec4199ae4ef4c6da05e7e4 paused=false running=false
ERRO[2024-10-15T11:13:38.772114505Z] failed to register container name: /217c53b9826eb7875ca2620596864d039848470befeb5f963b3ebffe509e7a6d container=b125af485d6d1875b586b314f93af1b49d5baaa94cec4199ae4ef4c6da05e7e4 error="container is already loaded"
And the conflicting container (`217c53b9826eb7875ca2620596864d039848470befeb5f963b3ebffe509e7a6d`)
is not present:
docker ps -a --no-trunc --format 'table {{.ID}}\t{{.Names}}'
CONTAINER ID NAMES
f59e8e4044471c45d4c9841d11a2c586cbfa4703b1344035fd51a15e15899ea7 b125af485d6d1875b586b314f93af1b49d5baaa94cec4199ae4ef4c6da05e7e4
b125af485d6d1875b586b314f93af1b49d5baaa94cec4199ae4ef4c6da05e7e4 217c53b9826eb7875ca2620596864d039848470befeb5f963b3ebffe509e7a6d
d54301b7560f3c3544acc2d9c9dd55a194d6db37c2af64fe83fa34238c7ce6ab one
[1]: 97b1233a15/daemon/names.go (L22-L38)
[2]: 97b1233a15/daemon/container.go (L106-L121)
[3]: 97b1233a15/daemon/container.go (L71-L76)
[4]: 97b1233a15/daemon/container.go (L30-L69)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This function only checked for the ID to be non-empty, and was only
used in a single location. Also move this check as first check in
registerName, to allow for an early return.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
The github.com/containerd/containerd/log package was moved to a separate
module, which will also be used by upcoming (patch) releases of containerd.
This patch moves our own uses of the package to use the new module.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
daemon.generateNewName() already reserves the generated name, but its name
did not indicate it did. The daemon.registerName() assumed that the generated
name still had to be reserved, which could mean it would try to reserve the
same name again.
This patch renames daemon.generateNewName to daemon.generateAndReserveName
to make it clearer what it does, and updates registerName() to return early
if it successfully generated (and registered) the container name.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Instead of having to create a bunch of custom error types that are doing
nothing but wrapping another error in sub-packages, use a common helper
to create errors of the requested type.
e.g. instead of re-implementing this over and over:
```go
type notFoundError struct {
cause error
}
func(e notFoundError) Error() string {
return e.cause.Error()
}
func(e notFoundError) NotFound() {}
func(e notFoundError) Cause() error {
return e.cause
}
```
Packages can instead just do:
```
errdefs.NotFound(err)
```
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Commit ebcb7d6b40 removed string checking
for error messages, in favor of typed errors.
In this change, the status code for conflicting container names
changed from 409 to 400 (validationError).
This patch add a `nameConflictError`, changing the status code to
409 as it was in older versions.
With this change applied, the correct 409 status is returned:
```bash
$ docker create --name c1 busybox
```
```bash
$ curl --unix-socket /var/run/docker.sock -v -XPOST -H"Content-Type: application/json" -d'{"Image":"busybox"}' http://localhost/containers/create?name=c1
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying /var/run/docker.sock...
* Connected to localhost (/var/run/docker.sock) port 80 (#0)
> POST /containers/create?name=c1 HTTP/1.1
> Host: localhost
> User-Agent: curl/7.52.1
> Accept: */*
> Content-Type: application/json
> Content-Length: 19
>
* upload completely sent off: 19 out of 19 bytes
< HTTP/1.1 409 Conflict
< Api-Version: 1.33
< Content-Type: application/json
< Docker-Experimental: false
< Ostype: linux
< Server: Docker/17.06.0-dev (linux)
< Date: Thu, 28 Sep 2017 15:07:23 GMT
< Content-Length: 229
<
{"message":"Conflict. The container name \"/c1\" is already in use by container \"ed2efdc806c1883954e677eb9ab8cbc7e286c9c5934ef6724fd5d93c56744923\". You have to remove (or rename) that container to be able to reuse that name."}
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact
```
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Use strongly typed errors to set HTTP status codes.
Error interfaces are defined in the api/errors package and errors
returned from controllers are checked against these interfaces.
Errors can be wraeped in a pkg/errors.Causer, as long as somewhere in the
line of causes one of the interfaces is implemented. The special error
interfaces take precedence over Causer, meaning if both Causer and one
of the new error interfaces are implemented, the Causer is not
traversed.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Currently, names are maintained by a separate system called "registrar".
This means there is no way to atomically snapshot the state of
containers and the names associated with them.
We can add this atomicity and simplify the code by storing name
associations in the memdb. This removes the need for pkg/registrar, and
makes snapshots a lot less expensive because they no longer need to copy
all the names. This change also avoids some problematic behavior from
pkg/registrar where it returns slices which may be modified later on.
Note that while this change makes the *snapshotting* atomic, it doesn't
yet do anything to make sure containers are named at the same time that
they are added to the database. We can do that by adding a transactional
interface, either as a followup, or as part of this PR.
Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
State will be saved on the following operation once the container is
properly registered on the daemon.
Signed-off-by: Fabio Kung <fabio.kung@gmail.com>
Use quoted form of container name and container id to improve copy-paste avoiding the extra `.` that slips into the clipboard
Signed-off-by: Jorge Marin <chipironcin@users.noreply.github.com>
This fix tries to address the issue raised in 28769 where
checkpoint name was not checked before passing to containerd.
As a result, it was possible to use a special checkpoint name
to get outside of the container's directory.
This fix add restriction `[a-zA-Z0-9][a-zA-Z0-9_.-]+` (`RestrictedNamePattern`).
This is the same as container name restriction.
This fix fixes 28769.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>