mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #6025 from crosbymichael/concurrent-names
Improve name generation on concurrent requests
This commit is contained in:
commit
0d9a5ce6dd
4 changed files with 63 additions and 80 deletions
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/dotcloud/docker/pkg/graphdb"
|
"github.com/dotcloud/docker/pkg/graphdb"
|
||||||
"github.com/dotcloud/docker/pkg/label"
|
"github.com/dotcloud/docker/pkg/label"
|
||||||
"github.com/dotcloud/docker/pkg/mount"
|
"github.com/dotcloud/docker/pkg/mount"
|
||||||
|
"github.com/dotcloud/docker/pkg/namesgenerator"
|
||||||
"github.com/dotcloud/docker/pkg/networkfs/resolvconf"
|
"github.com/dotcloud/docker/pkg/networkfs/resolvconf"
|
||||||
"github.com/dotcloud/docker/pkg/selinux"
|
"github.com/dotcloud/docker/pkg/selinux"
|
||||||
"github.com/dotcloud/docker/pkg/sysinfo"
|
"github.com/dotcloud/docker/pkg/sysinfo"
|
||||||
|
@ -250,20 +251,15 @@ func (daemon *Daemon) register(container *Container, updateSuffixarray bool) err
|
||||||
|
|
||||||
func (daemon *Daemon) ensureName(container *Container) error {
|
func (daemon *Daemon) ensureName(container *Container) error {
|
||||||
if container.Name == "" {
|
if container.Name == "" {
|
||||||
name, err := generateRandomName(daemon)
|
name, err := daemon.generateNewName(container.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
name = utils.TruncateID(container.ID)
|
return err
|
||||||
}
|
}
|
||||||
container.Name = name
|
container.Name = name
|
||||||
|
|
||||||
if err := container.ToDisk(); err != nil {
|
if err := container.ToDisk(); err != nil {
|
||||||
utils.Debugf("Error saving container name %s", err)
|
utils.Debugf("Error saving container name %s", err)
|
||||||
}
|
}
|
||||||
if !daemon.containerGraph.Exists(name) {
|
|
||||||
if _, err := daemon.containerGraph.Set(name, container.ID); err != nil {
|
|
||||||
utils.Debugf("Setting default id - %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -370,12 +366,8 @@ func (daemon *Daemon) restore() error {
|
||||||
// Any containers that are left over do not exist in the graph
|
// Any containers that are left over do not exist in the graph
|
||||||
for _, container := range containers {
|
for _, container := range containers {
|
||||||
// Try to set the default name for a container if it exists prior to links
|
// Try to set the default name for a container if it exists prior to links
|
||||||
container.Name, err = generateRandomName(daemon)
|
container.Name, err = daemon.generateNewName(container.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
container.Name = utils.TruncateID(container.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := daemon.containerGraph.Set(container.Name, container.ID); err != nil {
|
|
||||||
utils.Debugf("Setting default id - %s", err)
|
utils.Debugf("Setting default id - %s", err)
|
||||||
}
|
}
|
||||||
registerContainer(container)
|
registerContainer(container)
|
||||||
|
@ -470,42 +462,75 @@ func (daemon *Daemon) generateIdAndName(name string) (string, string, error) {
|
||||||
)
|
)
|
||||||
|
|
||||||
if name == "" {
|
if name == "" {
|
||||||
name, err = generateRandomName(daemon)
|
if name, err = daemon.generateNewName(id); err != nil {
|
||||||
if err != nil {
|
return "", "", err
|
||||||
name = utils.TruncateID(id)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !validContainerNamePattern.MatchString(name) {
|
|
||||||
return "", "", fmt.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars)
|
|
||||||
}
|
}
|
||||||
|
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(name) {
|
||||||
|
return "", fmt.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars)
|
||||||
|
}
|
||||||
|
|
||||||
if name[0] != '/' {
|
if name[0] != '/' {
|
||||||
name = "/" + name
|
name = "/" + name
|
||||||
}
|
}
|
||||||
// Set the enitity in the graph using the default name specified
|
|
||||||
if _, err := daemon.containerGraph.Set(name, id); err != nil {
|
if _, err := daemon.containerGraph.Set(name, id); err != nil {
|
||||||
if !graphdb.IsNonUniqueNameError(err) {
|
if !graphdb.IsNonUniqueNameError(err) {
|
||||||
return "", "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
conflictingContainer, err := daemon.GetByName(name)
|
conflictingContainer, err := daemon.GetByName(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "Could not find entity") {
|
if strings.Contains(err.Error(), "Could not find entity") {
|
||||||
return "", "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove name and continue starting the container
|
// Remove name and continue starting the container
|
||||||
if err := daemon.containerGraph.Delete(name); err != nil {
|
if err := daemon.containerGraph.Delete(name); err != nil {
|
||||||
return "", "", err
|
return "", err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
nameAsKnownByUser := strings.TrimPrefix(name, "/")
|
nameAsKnownByUser := strings.TrimPrefix(name, "/")
|
||||||
return "", "", fmt.Errorf(
|
return "", fmt.Errorf(
|
||||||
"Conflict, The name %s is already assigned to %s. You have to delete (or rename) that container to be able to assign %s to a container again.", nameAsKnownByUser,
|
"Conflict, The name %s is already assigned to %s. You have to delete (or rename) that container to be able to assign %s to a container again.", nameAsKnownByUser,
|
||||||
utils.TruncateID(conflictingContainer.ID), nameAsKnownByUser)
|
utils.TruncateID(conflictingContainer.ID), nameAsKnownByUser)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return id, name, nil
|
return name, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (daemon *Daemon) generateNewName(id string) (string, error) {
|
||||||
|
var name string
|
||||||
|
for i := 1; i < 6; i++ {
|
||||||
|
name = namesgenerator.GetRandomName(i)
|
||||||
|
if name[0] != '/' {
|
||||||
|
name = "/" + name
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := daemon.containerGraph.Set(name, id); err != nil {
|
||||||
|
if !graphdb.IsNonUniqueNameError(err) {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return name, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
name = "/" + utils.TruncateID(id)
|
||||||
|
if _, err := daemon.containerGraph.Set(name, id); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) generateHostname(id string, config *runconfig.Config) {
|
func (daemon *Daemon) generateHostname(id string, config *runconfig.Config) {
|
||||||
|
|
|
@ -2,10 +2,10 @@ package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dotcloud/docker/nat"
|
|
||||||
"github.com/dotcloud/docker/pkg/namesgenerator"
|
|
||||||
"github.com/dotcloud/docker/runconfig"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/dotcloud/docker/nat"
|
||||||
|
"github.com/dotcloud/docker/runconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
func migratePortMappings(config *runconfig.Config, hostConfig *runconfig.HostConfig) error {
|
func migratePortMappings(config *runconfig.Config, hostConfig *runconfig.HostConfig) error {
|
||||||
|
@ -49,16 +49,3 @@ func mergeLxcConfIntoOptions(hostConfig *runconfig.HostConfig, driverConfig map[
|
||||||
driverConfig["lxc"] = lxc
|
driverConfig["lxc"] = lxc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type checker struct {
|
|
||||||
daemon *Daemon
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *checker) Exists(name string) bool {
|
|
||||||
return c.daemon.containerGraph.Exists("/" + name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a random and unique name
|
|
||||||
func generateRandomName(daemon *Daemon) (string, error) {
|
|
||||||
return namesgenerator.GenerateRandomName(&checker{daemon})
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,10 +6,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NameChecker interface {
|
|
||||||
Exists(name string) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
left = [...]string{"happy", "jolly", "dreamy", "sad", "angry", "pensive", "focused", "sleepy", "grave", "distracted", "determined", "stoic", "stupefied", "sharp", "agitated", "cocky", "tender", "goofy", "furious", "desperate", "hopeful", "compassionate", "silly", "lonely", "condescending", "naughty", "kickass", "drunk", "boring", "nostalgic", "ecstatic", "insane", "cranky", "mad", "jovial", "sick", "hungry", "thirsty", "elegant", "backstabbing", "clever", "trusting", "loving", "suspicious", "berserk", "high", "romantic", "prickly", "evil"}
|
left = [...]string{"happy", "jolly", "dreamy", "sad", "angry", "pensive", "focused", "sleepy", "grave", "distracted", "determined", "stoic", "stupefied", "sharp", "agitated", "cocky", "tender", "goofy", "furious", "desperate", "hopeful", "compassionate", "silly", "lonely", "condescending", "naughty", "kickass", "drunk", "boring", "nostalgic", "ecstatic", "insane", "cranky", "mad", "jovial", "sick", "hungry", "thirsty", "elegant", "backstabbing", "clever", "trusting", "loving", "suspicious", "berserk", "high", "romantic", "prickly", "evil"}
|
||||||
// Docker 0.7.x generates names from notable scientists and hackers.
|
// Docker 0.7.x generates names from notable scientists and hackers.
|
||||||
|
@ -79,16 +75,17 @@ var (
|
||||||
right = [...]string{"lovelace", "franklin", "tesla", "einstein", "bohr", "davinci", "pasteur", "nobel", "curie", "darwin", "turing", "ritchie", "torvalds", "pike", "thompson", "wozniak", "galileo", "euclid", "newton", "fermat", "archimedes", "poincare", "heisenberg", "feynman", "hawking", "fermi", "pare", "mccarthy", "engelbart", "babbage", "albattani", "ptolemy", "bell", "wright", "lumiere", "morse", "mclean", "brown", "bardeen", "brattain", "shockley", "goldstine", "hoover", "hopper", "bartik", "sammet", "jones", "perlman", "wilson", "kowalevski", "hypatia", "goodall", "mayer", "elion", "blackwell", "lalande", "kirch", "ardinghelli", "colden", "almeida", "leakey", "meitner", "mestorf", "rosalind", "sinoussi", "carson", "mcclintock", "yonath"}
|
right = [...]string{"lovelace", "franklin", "tesla", "einstein", "bohr", "davinci", "pasteur", "nobel", "curie", "darwin", "turing", "ritchie", "torvalds", "pike", "thompson", "wozniak", "galileo", "euclid", "newton", "fermat", "archimedes", "poincare", "heisenberg", "feynman", "hawking", "fermi", "pare", "mccarthy", "engelbart", "babbage", "albattani", "ptolemy", "bell", "wright", "lumiere", "morse", "mclean", "brown", "bardeen", "brattain", "shockley", "goldstine", "hoover", "hopper", "bartik", "sammet", "jones", "perlman", "wilson", "kowalevski", "hypatia", "goodall", "mayer", "elion", "blackwell", "lalande", "kirch", "ardinghelli", "colden", "almeida", "leakey", "meitner", "mestorf", "rosalind", "sinoussi", "carson", "mcclintock", "yonath"}
|
||||||
)
|
)
|
||||||
|
|
||||||
func GenerateRandomName(checker NameChecker) (string, error) {
|
func GetRandomName(retry int) string {
|
||||||
retry := 5
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
|
begin:
|
||||||
name := fmt.Sprintf("%s_%s", left[rand.Intn(len(left))], right[rand.Intn(len(right))])
|
name := fmt.Sprintf("%s_%s", left[rand.Intn(len(left))], right[rand.Intn(len(right))])
|
||||||
for checker != nil && checker.Exists(name) && retry > 0 || name == "boring_wozniak" /* Steve Wozniak is not boring */ {
|
if name == "boring_wozniak" /* Steve Wozniak is not boring */ {
|
||||||
|
goto begin
|
||||||
|
}
|
||||||
|
|
||||||
|
if retry > 0 {
|
||||||
name = fmt.Sprintf("%s%d", name, rand.Intn(10))
|
name = fmt.Sprintf("%s%d", name, rand.Intn(10))
|
||||||
retry = retry - 1
|
|
||||||
}
|
}
|
||||||
if retry == 0 {
|
return name
|
||||||
return name, fmt.Errorf("Error generating random name")
|
|
||||||
}
|
|
||||||
return name, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,35 +4,9 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FalseChecker struct{}
|
|
||||||
|
|
||||||
func (n *FalseChecker) Exists(name string) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type TrueChecker struct{}
|
|
||||||
|
|
||||||
func (n *TrueChecker) Exists(name string) bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGenerateRandomName(t *testing.T) {
|
|
||||||
if _, err := GenerateRandomName(&FalseChecker{}); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := GenerateRandomName(&TrueChecker{}); err == nil {
|
|
||||||
t.Error("An error was expected")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the generated names are awesome
|
// Make sure the generated names are awesome
|
||||||
func TestGenerateAwesomeNames(t *testing.T) {
|
func TestGenerateAwesomeNames(t *testing.T) {
|
||||||
name, err := GenerateRandomName(&FalseChecker{})
|
name := GetRandomName(0)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
if !isAwesome(name) {
|
if !isAwesome(name) {
|
||||||
t.Fatalf("Generated name '%s' is not awesome.", name)
|
t.Fatalf("Generated name '%s' is not awesome.", name)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue