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 := range 6 { 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 }