1package daemon // import "github.com/docker/docker/daemon"
2
3import (
4	"fmt"
5	"strings"
6
7	"github.com/docker/docker/container"
8	"github.com/docker/docker/daemon/names"
9	"github.com/docker/docker/errdefs"
10	"github.com/docker/docker/pkg/namesgenerator"
11	"github.com/docker/docker/pkg/stringid"
12	"github.com/pkg/errors"
13	"github.com/sirupsen/logrus"
14)
15
16var (
17	validContainerNameChars   = names.RestrictedNameChars
18	validContainerNamePattern = names.RestrictedNamePattern
19)
20
21func (daemon *Daemon) registerName(container *container.Container) error {
22	if daemon.Exists(container.ID) {
23		return fmt.Errorf("Container is already loaded")
24	}
25	if err := validateID(container.ID); err != nil {
26		return err
27	}
28	if container.Name == "" {
29		name, err := daemon.generateNewName(container.ID)
30		if err != nil {
31			return err
32		}
33		container.Name = name
34	}
35	return daemon.containersReplica.ReserveName(container.Name, container.ID)
36}
37
38func (daemon *Daemon) generateIDAndName(name string) (string, string, error) {
39	var (
40		err error
41		id  = stringid.GenerateNonCryptoID()
42	)
43
44	if name == "" {
45		if name, err = daemon.generateNewName(id); err != nil {
46			return "", "", err
47		}
48		return id, name, nil
49	}
50
51	if name, err = daemon.reserveName(id, name); err != nil {
52		return "", "", err
53	}
54
55	return id, name, nil
56}
57
58func (daemon *Daemon) reserveName(id, name string) (string, error) {
59	if !validContainerNamePattern.MatchString(strings.TrimPrefix(name, "/")) {
60		return "", errdefs.InvalidParameter(errors.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars))
61	}
62	if name[0] != '/' {
63		name = "/" + name
64	}
65
66	if err := daemon.containersReplica.ReserveName(name, id); err != nil {
67		if err == container.ErrNameReserved {
68			id, err := daemon.containersReplica.Snapshot().GetID(name)
69			if err != nil {
70				logrus.Errorf("got unexpected error while looking up reserved name: %v", err)
71				return "", err
72			}
73			return "", nameConflictError{id: id, name: name}
74		}
75		return "", errors.Wrapf(err, "error reserving name: %q", name)
76	}
77	return name, nil
78}
79
80func (daemon *Daemon) releaseName(name string) {
81	daemon.containersReplica.ReleaseName(name)
82}
83
84func (daemon *Daemon) generateNewName(id string) (string, error) {
85	var name string
86	for i := 0; i < 6; i++ {
87		name = namesgenerator.GetRandomName(i)
88		if name[0] != '/' {
89			name = "/" + name
90		}
91
92		if err := daemon.containersReplica.ReserveName(name, id); err != nil {
93			if err == container.ErrNameReserved {
94				continue
95			}
96			return "", err
97		}
98		return name, nil
99	}
100
101	name = "/" + stringid.TruncateID(id)
102	if err := daemon.containersReplica.ReserveName(name, id); err != nil {
103		return "", err
104	}
105	return name, nil
106}
107
108func validateID(id string) error {
109	if id == "" {
110		return fmt.Errorf("Invalid empty id")
111	}
112	return nil
113}
114