e424343b43
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>
112 lines
2.6 KiB
Go
112 lines
2.6 KiB
Go
package daemon
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/docker/docker/container"
|
|
"github.com/docker/docker/daemon/names"
|
|
"github.com/docker/docker/pkg/namesgenerator"
|
|
"github.com/docker/docker/pkg/stringid"
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var (
|
|
validContainerNameChars = names.RestrictedNameChars
|
|
validContainerNamePattern = names.RestrictedNamePattern
|
|
)
|
|
|
|
func (daemon *Daemon) registerName(container *container.Container) error {
|
|
if daemon.Exists(container.ID) {
|
|
return fmt.Errorf("Container is already loaded")
|
|
}
|
|
if err := validateID(container.ID); err != nil {
|
|
return err
|
|
}
|
|
if container.Name == "" {
|
|
name, err := daemon.generateNewName(container.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
container.Name = name
|
|
}
|
|
return daemon.containersReplica.ReserveName(container.Name, container.ID)
|
|
}
|
|
|
|
func (daemon *Daemon) generateIDAndName(name string) (string, string, error) {
|
|
var (
|
|
err error
|
|
id = stringid.GenerateNonCryptoID()
|
|
)
|
|
|
|
if name == "" {
|
|
if name, err = daemon.generateNewName(id); err != nil {
|
|
return "", "", err
|
|
}
|
|
return id, name, nil
|
|
}
|
|
|
|
if name, err = daemon.reserveName(id, name); err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
return id, name, nil
|
|
}
|
|
|
|
func (daemon *Daemon) reserveName(id, name string) (string, error) {
|
|
if !validContainerNamePattern.MatchString(strings.TrimPrefix(name, "/")) {
|
|
return "", validationError{errors.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars)}
|
|
}
|
|
if name[0] != '/' {
|
|
name = "/" + name
|
|
}
|
|
|
|
if err := daemon.containersReplica.ReserveName(name, id); err != nil {
|
|
if err == container.ErrNameReserved {
|
|
id, err := daemon.containersReplica.Snapshot().GetID(name)
|
|
if err != nil {
|
|
logrus.Errorf("got unexpected error while looking up reserved name: %v", err)
|
|
return "", err
|
|
}
|
|
return "", nameConflictError{id: id, name: name}
|
|
}
|
|
return "", errors.Wrapf(err, "error reserving name: %q", name)
|
|
}
|
|
return name, nil
|
|
}
|
|
|
|
func (daemon *Daemon) releaseName(name string) {
|
|
daemon.containersReplica.ReleaseName(name)
|
|
}
|
|
|
|
func (daemon *Daemon) generateNewName(id string) (string, error) {
|
|
var name string
|
|
for i := 0; i < 6; i++ {
|
|
name = namesgenerator.GetRandomName(i)
|
|
if name[0] != '/' {
|
|
name = "/" + name
|
|
}
|
|
|
|
if err := daemon.containersReplica.ReserveName(name, id); err != nil {
|
|
if err == container.ErrNameReserved {
|
|
continue
|
|
}
|
|
return "", err
|
|
}
|
|
return name, nil
|
|
}
|
|
|
|
name = "/" + stringid.TruncateID(id)
|
|
if err := daemon.containersReplica.ReserveName(name, id); err != nil {
|
|
return "", err
|
|
}
|
|
return name, nil
|
|
}
|
|
|
|
func validateID(id string) error {
|
|
if id == "" {
|
|
return fmt.Errorf("Invalid empty id")
|
|
}
|
|
return nil
|
|
}
|