diff --git a/container/container.go b/container/container.go index 7d21d1d1..c2661bba 100644 --- a/container/container.go +++ b/container/container.go @@ -32,7 +32,7 @@ type ListType int type ContainerHandler interface { GetSpec() (*info.ContainerSpec, error) GetStats() (*info.ContainerStats, error) - ListContainers(listType ListType) ([]string, error) + ListContainers(listType ListType) ([]info.ContainerReference, error) ListThreads(listType ListType) ([]int, error) ListProcesses(listType ListType) ([]int, error) StatsSummary() (*info.ContainerStatsPercentiles, error) diff --git a/container/docker/handler.go b/container/docker/handler.go index 80cb7fc7..5952e72c 100644 --- a/container/docker/handler.go +++ b/container/docker/handler.go @@ -285,12 +285,12 @@ func (self *dockerContainerHandler) GetStats() (stats *info.ContainerStats, err return } -func (self *dockerContainerHandler) ListContainers(listType container.ListType) ([]string, error) { +func (self *dockerContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) { if self.isDockerContainer() { return nil, nil } if self.isRootContainer() && listType == container.LIST_SELF { - return []string{"/docker"}, nil + return []info.ContainerReference{info.ContainerReference{Name: "/docker"}}, nil } opt := docker.ListContainersOptions{ All: true, @@ -299,16 +299,21 @@ func (self *dockerContainerHandler) ListContainers(listType container.ListType) if err != nil { return nil, err } - ret := make([]string, 0, len(containers)+1) + ret := make([]info.ContainerReference, 0, len(containers)+1) for _, c := range containers { if !strings.HasPrefix(c.Status, "Up ") { continue } path := fmt.Sprintf("/docker/%v", c.ID) - ret = append(ret, path) + aliases := c.Names + ref := info.ContainerReference{ + Name: path, + Aliases: aliases, + } + ret = append(ret, ref) } if self.isRootContainer() { - ret = append(ret, "/docker") + ret = append(ret, info.ContainerReference{Name: "/docker"}) } return ret, nil } diff --git a/container/filter.go b/container/filter.go index 0495bdc7..0d262c3f 100644 --- a/container/filter.go +++ b/container/filter.go @@ -34,7 +34,7 @@ func (self *containerListFilter) GetStats() (*info.ContainerStats, error) { return self.handler.GetStats() } -func (self *containerListFilter) ListContainers(listType ListType) ([]string, error) { +func (self *containerListFilter) ListContainers(listType ListType) ([]info.ContainerReference, error) { containers, err := self.handler.ListContainers(listType) if err != nil { return nil, err @@ -42,9 +42,9 @@ func (self *containerListFilter) ListContainers(listType ListType) ([]string, er if len(containers) == 0 { return nil, nil } - ret := make([]string, 0, len(containers)) + ret := make([]info.ContainerReference, 0, len(containers)) for _, c := range containers { - if self.filter(c) { + if self.filter(c.Name) { ret = append(ret, c) } } diff --git a/container/filter_test.go b/container/filter_test.go index b6c2d41a..3a3a3d46 100644 --- a/container/filter_test.go +++ b/container/filter_test.go @@ -37,9 +37,9 @@ func (self *mockContainerHandler) GetStats() (*info.ContainerStats, error) { return args.Get(0).(*info.ContainerStats), args.Error(1) } -func (self *mockContainerHandler) ListContainers(listType ListType) ([]string, error) { +func (self *mockContainerHandler) ListContainers(listType ListType) ([]info.ContainerReference, error) { args := self.Called(listType) - return args.Get(0).([]string), args.Error(1) + return args.Get(0).([]info.ContainerReference), args.Error(1) } func (self *mockContainerHandler) ListThreads(listType ListType) ([]int, error) { @@ -55,10 +55,10 @@ func (self *mockContainerHandler) ListProcesses(listType ListType) ([]int, error func TestWhiteListContainerFilter(t *testing.T) { mockc := &mockContainerHandler{} mockc.On("ListContainers", LIST_RECURSIVE).Return( - []string{ - "/docker/ee0103", - "/container/created/by/lmctfy", - "/user/something", + []info.ContainerReference{ + info.ContainerReference{Name: "/docker/ee0103"}, + info.ContainerReference{Name: "/container/created/by/lmctfy"}, + info.ContainerReference{Name: "/user/something"}, }, nil, ) @@ -76,7 +76,7 @@ func TestWhiteListContainerFilter(t *testing.T) { for _, c := range containers { legal := false for _, prefix := range filterPaths { - if strings.HasPrefix(c, prefix) { + if strings.HasPrefix(c.Name, prefix) { legal = true } } @@ -90,10 +90,10 @@ func TestWhiteListContainerFilter(t *testing.T) { func TestBlackListContainerFilter(t *testing.T) { mockc := &mockContainerHandler{} mockc.On("ListContainers", LIST_RECURSIVE).Return( - []string{ - "/docker/ee0103", - "/container/created/by/lmctfy", - "/user/something", + []info.ContainerReference{ + info.ContainerReference{Name: "/docker/ee0103"}, + info.ContainerReference{Name: "/container/created/by/lmctfy"}, + info.ContainerReference{Name: "/user/something"}, }, nil, ) @@ -111,7 +111,7 @@ func TestBlackListContainerFilter(t *testing.T) { for _, c := range containers { legal := true for _, prefix := range filterPaths { - if strings.HasPrefix(c, prefix) { + if strings.HasPrefix(c.Name, prefix) { legal = false } } diff --git a/container/lmctfy/lmctfy_container.go b/container/lmctfy/lmctfy_container.go index d0d33860..24e06cee 100644 --- a/container/lmctfy/lmctfy_container.go +++ b/container/lmctfy/lmctfy_container.go @@ -157,7 +157,7 @@ func (c *lmctfyContainerHandler) GetStats() (*info.ContainerStats, error) { } // Gets all subcontainers. -func (c *lmctfyContainerHandler) ListContainers(listType container.ListType) ([]string, error) { +func (c *lmctfyContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) { // Prepare the arguments. args := []string{"list", "containers", "-v"} if listType == container.LIST_RECURSIVE { @@ -174,13 +174,14 @@ func (c *lmctfyContainerHandler) ListContainers(listType container.ListType) ([] // Parse lines as container names. if len(data) == 0 { - return []string{}, nil + return nil, nil } names := strings.Split(string(data), "\n") - containerNames := make([]string, 0, len(names)) + containerNames := make([]info.ContainerReference, 0, len(names)) for _, name := range names { if len(name) != 0 { - containerNames = append(containerNames, name) + ref := info.ContainerReference{Name: name} + containerNames = append(containerNames, ref) } } return containerNames, nil diff --git a/container/statssum.go b/container/statssum.go index 081e6667..b562d93b 100644 --- a/container/statssum.go +++ b/container/statssum.go @@ -94,7 +94,7 @@ func (self *percentilesContainerHandlerWrapper) GetStats() (*info.ContainerStats return stats, nil } -func (self *percentilesContainerHandlerWrapper) ListContainers(listType ListType) ([]string, error) { +func (self *percentilesContainerHandlerWrapper) ListContainers(listType ListType) ([]info.ContainerReference, error) { return self.handler.ListContainers(listType) } diff --git a/container/statssum_test.go b/container/statssum_test.go index 0c020e12..bd31fdb4 100644 --- a/container/statssum_test.go +++ b/container/statssum_test.go @@ -29,7 +29,7 @@ type mockContainer struct { func (self *mockContainer) GetSpec() (*info.ContainerSpec, error) { return nil, nil } -func (self *mockContainer) ListContainers(listType ListType) ([]string, error) { +func (self *mockContainer) ListContainers(listType ListType) ([]info.ContainerReference, error) { return nil, nil } diff --git a/info/container.go b/info/container.go index fe9245b0..87d00dbb 100644 --- a/info/container.go +++ b/info/container.go @@ -49,12 +49,19 @@ type ContainerSpec struct { Memory *MemorySpec `json:"memory,omitempty"` } -type ContainerInfo struct { +// Container reference contains enough information to uniquely identify a container +type ContainerReference struct { // The absolute name of the container. Name string `json:"name"` + Aliases []string `json:"aliases,omitempty"` +} + +type ContainerInfo struct { + ContainerReference + // The direct subcontainers of the current container. - Subcontainers []string `json:"subcontainers,omitempty"` + Subcontainers []ContainerReference `json:"subcontainers,omitempty"` // The isolation used in the container. Spec *ContainerSpec `json:"spec,omitempty"` diff --git a/info/container_test.go b/info/container_test.go index bf449a4e..4b275bec 100644 --- a/info/container_test.go +++ b/info/container_test.go @@ -30,7 +30,9 @@ func TestStatsStartTime(t *testing.T) { stats = append(stats, s) } cinfo := &ContainerInfo{ - Name: "/some/container", + ContainerReference: ContainerReference{ + Name: "/some/container", + }, Stats: stats, } ref := ct.Add(time.Duration(N-1) * time.Second) @@ -52,7 +54,9 @@ func TestStatsEndTime(t *testing.T) { stats = append(stats, s) } cinfo := &ContainerInfo{ - Name: "/some/container", + ContainerReference: ContainerReference{ + Name: "/some/container", + }, Stats: stats, } ref := ct diff --git a/manager/container.go b/manager/container.go index be7eea1e..59e1bdcd 100644 --- a/manager/container.go +++ b/manager/container.go @@ -35,11 +35,11 @@ type containerStat struct { Data *info.ContainerStats } type containerInfo struct { - Name string - Subcontainers []string - Spec *info.ContainerSpec - Stats *list.List - StatsSummary *info.ContainerStatsPercentiles + info.ContainerReference + Subcontainers []info.ContainerReference + Spec *info.ContainerSpec + Stats *list.List + StatsSummary *info.ContainerStatsPercentiles } type containerData struct { diff --git a/manager/manager.go b/manager/manager.go index 6320fa19..3df5c927 100644 --- a/manager/manager.go +++ b/manager/manager.go @@ -111,7 +111,9 @@ func (m *manager) GetContainerInfo(containerName string) (*info.ContainerInfo, e // Make a copy of the info for the user. ret := &info.ContainerInfo{ - Name: cinfo.Name, + ContainerReference: info.ContainerReference{ + Name: cinfo.Name, + }, Subcontainers: cinfo.Subcontainers, Spec: cinfo.Spec, StatsSummary: cinfo.StatsSummary, @@ -180,10 +182,8 @@ func (m *manager) destroyContainer(containerName string) error { return nil } -type empty struct{} - // Detect all containers that have been added or deleted. -func (m *manager) getContainersDiff() (added []string, removed []string, err error) { +func (m *manager) getContainersDiff() (added []info.ContainerReference, removed []info.ContainerReference, err error) { // TODO(vmarmol): We probably don't need to lock around / since it will always be there. m.containersLock.RLock() defer m.containersLock.RUnlock() @@ -197,24 +197,24 @@ func (m *manager) getContainersDiff() (added []string, removed []string, err err if err != nil { return nil, nil, err } - allContainers = append(allContainers, "/") + allContainers = append(allContainers, info.ContainerReference{Name: "/"}) // Determine which were added and which were removed. - allContainersSet := make(map[string]*empty) - for name, _ := range m.containers { - allContainersSet[name] = &empty{} + allContainersSet := make(map[string]*containerData) + for name, d := range m.containers { + allContainersSet[name] = d } - for _, name := range allContainers { - delete(allContainersSet, name) - _, ok := m.containers[name] + for _, c := range allContainers { + delete(allContainersSet, c.Name) + _, ok := m.containers[c.Name] if !ok { - added = append(added, name) + added = append(added, c) } } // Removed ones are no longer in the container listing. - for name, _ := range allContainersSet { - removed = append(removed, name) + for _, d := range allContainersSet { + removed = append(removed, d.info.ContainerReference) } return @@ -228,18 +228,18 @@ func (m *manager) detectContainers() error { } // Add the new containers. - for _, name := range added { - _, err = m.createContainer(name) + for _, container := range added { + _, err = m.createContainer(container.Name) if err != nil { - return fmt.Errorf("Failed to create existing container: %s: %s", name, err) + return fmt.Errorf("Failed to create existing container: %s: %s", container.Name, err) } } // Remove the old containers. - for _, name := range removed { - err = m.destroyContainer(name) + for _, container := range removed { + err = m.destroyContainer(container.Name) if err != nil { - return fmt.Errorf("Failed to destroy existing container: %s: %s", name, err) + return fmt.Errorf("Failed to destroy existing container: %s: %s", container.Name, err) } } diff --git a/pages/containers.go b/pages/containers.go index 8efb84d2..60034cec 100644 --- a/pages/containers.go +++ b/pages/containers.go @@ -50,8 +50,8 @@ var pageTemplate *template.Template type pageData struct { ContainerName string - ParentContainers []string - Subcontainers []string + ParentContainers []info.ContainerReference + Subcontainers []info.ContainerReference Spec *info.ContainerSpec Stats []*info.ContainerStats MachineInfo *info.MachineInfo @@ -69,14 +69,17 @@ func init() { } // TODO(vmarmol): Escape this correctly. -func containerLink(containerName string, basenameOnly bool, cssClasses string) interface{} { +func containerLink(container info.ContainerReference, basenameOnly bool, cssClasses string) interface{} { var displayName string - if basenameOnly { - displayName = path.Base(string(containerName)) + containerName := container.Name + if len(container.Aliases) > 0 { + displayName = container.Aliases[0] + } else if basenameOnly { + displayName = path.Base(string(container.Name)) } else { - displayName = string(containerName) + displayName = string(container.Name) } - if containerName == "root" { + if container.Name == "root" { containerName = "/" } return template.HTML(fmt.Sprintf("%s", cssClasses, ContainersPage[:len(ContainersPage)-1], containerName, displayName)) @@ -167,15 +170,15 @@ func ServerContainersPage(m manager.Manager, w http.ResponseWriter, u *url.URL) } // Make a list of the parent containers and their links - var parentContainers []string - parentContainers = append(parentContainers, string("root")) + var parentContainers []info.ContainerReference + parentContainers = append(parentContainers, info.ContainerReference{Name: "root"}) parentName := "" for _, part := range strings.Split(string(cont.Name), "/") { if part == "" { continue } parentName += "/" + part - parentContainers = append(parentContainers, string(parentName)) + parentContainers = append(parentContainers, info.ContainerReference{Name: parentName}) } data := &pageData{