From 356af1540f9a43337571e0f3ad6038789b38478e Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Thu, 24 Oct 2013 16:49:28 -0700 Subject: [PATCH] Ensure child containers are started before parents --- gograph/gograph.go | 2 +- gograph/sort.go | 2 +- gograph/utils.go | 2 +- runtime.go | 67 ++++++++++++++++++++++++++++------------------ runtime_test.go | 4 +-- 5 files changed, 46 insertions(+), 31 deletions(-) diff --git a/gograph/gograph.go b/gograph/gograph.go index 9f477c4cf5..48693d3ec3 100644 --- a/gograph/gograph.go +++ b/gograph/gograph.go @@ -177,7 +177,7 @@ func (db *Database) get(name string) (*Entity, error) { next := db.child(e, p) if next == nil { - return nil, fmt.Errorf("Cannot find child") + return nil, fmt.Errorf("Cannot find child for %s", name) } e = next } diff --git a/gograph/sort.go b/gograph/sort.go index cc936cb840..a0af6b4025 100644 --- a/gograph/sort.go +++ b/gograph/sort.go @@ -9,7 +9,7 @@ type pathSorter struct { func sortByDepth(paths []string) { s := &pathSorter{paths, func(i, j string) bool { - return pathDepth(i) > pathDepth(j) + return PathDepth(i) > PathDepth(j) }} sort.Sort(s) } diff --git a/gograph/utils.go b/gograph/utils.go index c20dd124a2..4896242796 100644 --- a/gograph/utils.go +++ b/gograph/utils.go @@ -11,7 +11,7 @@ func split(p string) []string { } // Returns the depth or number of / in a given path -func pathDepth(p string) int { +func PathDepth(p string) int { parts := split(p) if len(parts) == 2 && parts[1] == "" { return 1 diff --git a/runtime.go b/runtime.go index 9ac9269317..58c2007f7b 100644 --- a/runtime.go +++ b/runtime.go @@ -230,7 +230,8 @@ func (runtime *Runtime) restore() error { if err != nil { return err } - containers := []*Container{} + containers := make(map[string]*Container) + for i, v := range dir { id := v.Name() container, err := runtime.load(id) @@ -242,33 +243,34 @@ func (runtime *Runtime) restore() error { continue } utils.Debugf("Loaded container %v", container.ID) - containers = append(containers, container) + containers[container.ID] = container } - sortContainers(containers, func(i, j *Container) bool { - ic, _ := i.ReadHostConfig() - jc, _ := j.ReadHostConfig() - if ic == nil || ic.Links == nil { - return true + register := func(container *Container) { + if err := runtime.Register(container); err != nil { + utils.Debugf("Failed to register container %s: %s", container.ID, err) } - if jc == nil || jc.Links == nil { - return false + } + + if entities := runtime.containerGraph.List("/", -1); entities != nil { + for _, p := range entities.Paths() { + e := entities[p] + if container, ok := containers[e.ID()]; ok { + register(container) + delete(containers, e.ID()) + } } - return len(ic.Links) < len(jc.Links) - }) + } + + // Any containers that are left over do not exist in the graph for _, container := range containers { - // Try to set the default name for a container if it exists prior to links - // Ignore the error because if it already exists you will get an invalid constraint if _, err := runtime.containerGraph.Set(fmt.Sprintf("/%s", container.ID), container.ID); err != nil { utils.Debugf("Setting default id - %s", err) } - - if err := runtime.Register(container); err != nil { - utils.Debugf("Failed to register container %s: %s", container.ID, err) - continue - } + register(container) } + if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" { fmt.Printf("\bdone.\n") } @@ -481,14 +483,24 @@ func (runtime *Runtime) Commit(container *Container, repository, tag, comment, a return img, nil } -func (runtime *Runtime) GetByName(name string) (*Container, error) { - if name[0] != '/' { - name = "/" + name +// Strip the leading slash from the name to look up if it +// is a truncated id +// Prepend the slash back after finding the name +func (runtime *Runtime) getFullName(name string) string { + if name[0] == '/' { + name = name[1:] } - if id, err := runtime.idIndex.Get(name); err == nil { name = id } + if name[0] != '/' { + name = "/" + name + } + return name +} + +func (runtime *Runtime) GetByName(name string) (*Container, error) { + name = runtime.getFullName(name) entity := runtime.containerGraph.Get(name) if entity == nil { @@ -520,17 +532,20 @@ func (runtime *Runtime) Children(name string) (map[string]*Container, error) { } func (runtime *Runtime) RenameLink(oldName, newName string) error { - if id, err := runtime.idIndex.Get(oldName); err == nil { - oldName = id - } + oldName = runtime.getFullName(oldName) + entity := runtime.containerGraph.Get(oldName) if entity == nil { return fmt.Errorf("Could not find entity for %s", oldName) } + if newName[0] != '/' { + newName = "/" + newName + } + // This is not rename but adding a new link for the default name // Strip the leading '/' - if strings.HasPrefix(entity.ID(), oldName[1:]) { + if entity.ID() == oldName[1:] { _, err := runtime.containerGraph.Set(newName, entity.ID()) return err } diff --git a/runtime_test.go b/runtime_test.go index 040d06851e..085e5be1a3 100644 --- a/runtime_test.go +++ b/runtime_test.go @@ -572,7 +572,7 @@ func TestReloadContainerLinks(t *testing.T) { } h1 := &HostConfig{} // Add a link to container 2 - h1.Links = []string{utils.TruncateID(container2.ID) + ":first"} + h1.Links = []string{"/" + container2.ID + ":first"} if err := container1.Start(h1); err != nil { t.Fatal(err) } @@ -618,7 +618,7 @@ func TestReloadContainerLinks(t *testing.T) { t.Fatalf("Container 2 %s should be registered first in the runtime", container2.ID) } - t.Logf("Number of links: %d", runtime2.containerGraph.Refs("engine")) + t.Logf("Number of links: %d", runtime2.containerGraph.Refs("0")) // Verify that the link is still registered in the runtime entity := runtime2.containerGraph.Get(fmt.Sprintf("/%s", container1.ID)) if entity == nil {