| package daemon |
| |
| import ( |
| "context" |
| "strings" |
| |
| cerrdefs "github.com/containerd/errdefs" |
| "github.com/containerd/log" |
| "github.com/moby/moby/v2/daemon/container" |
| "github.com/moby/moby/v2/daemon/internal/stringid" |
| "github.com/moby/moby/v2/daemon/names" |
| "github.com/moby/moby/v2/errdefs" |
| "github.com/moby/moby/v2/internal/namesgenerator" |
| "github.com/pkg/errors" |
| ) |
| |
| var ( |
| validContainerNameChars = names.RestrictedNameChars |
| validContainerNamePattern = names.RestrictedNamePattern |
| ) |
| |
| func (daemon *Daemon) registerName(container *container.Container) error { |
| if container.ID == "" { |
| return errors.New("invalid empty id") |
| } |
| if daemon.containers.Get(container.ID) != nil { |
| // TODO(thaJeztah): should this be a panic (duplicate IDs due to invalid state on disk?) |
| // TODO(thaJeztah): should this also check for container.ID being a prefix of another container's ID? (daemon.containersReplica.GetByPrefix); only should happen due to corruption / truncated ID. |
| return errors.New("container is already loaded") |
| } |
| if container.Name == "" { |
| name, err := daemon.generateAndReserveName(container.ID) |
| if err != nil { |
| return err |
| } |
| container.Name = name |
| return nil |
| } |
| return daemon.containersReplica.ReserveName(container.Name, container.ID) |
| } |
| |
| func (daemon *Daemon) generateIDAndName(name string) (string, string, error) { |
| var ( |
| err error |
| id = stringid.GenerateRandomID() |
| ) |
| |
| if name == "" { |
| if name, err = daemon.generateAndReserveName(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 "", errdefs.InvalidParameter(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 cerrdefs.IsConflict(err) { |
| id, err := daemon.containersReplica.Snapshot().GetID(name) |
| if err != nil { |
| log.G(context.TODO()).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) generateAndReserveName(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 cerrdefs.IsConflict(err) { |
| continue |
| } |
| return "", err |
| } |
| return name, nil |
| } |
| |
| name = "/" + stringid.TruncateID(id) |
| if err := daemon.containersReplica.ReserveName(name, id); err != nil { |
| return "", err |
| } |
| return name, nil |
| } |