Merge pull request #28 from monnand/docker-alias

Displays docker container's name
This commit is contained in:
Victor Marmol 2014-06-12 17:38:38 -07:00
commit 7126b1408c
12 changed files with 86 additions and 66 deletions

View File

@ -32,7 +32,7 @@ type ListType int
type ContainerHandler interface { type ContainerHandler interface {
GetSpec() (*info.ContainerSpec, error) GetSpec() (*info.ContainerSpec, error)
GetStats() (*info.ContainerStats, error) GetStats() (*info.ContainerStats, error)
ListContainers(listType ListType) ([]string, error) ListContainers(listType ListType) ([]info.ContainerReference, error)
ListThreads(listType ListType) ([]int, error) ListThreads(listType ListType) ([]int, error)
ListProcesses(listType ListType) ([]int, error) ListProcesses(listType ListType) ([]int, error)
StatsSummary() (*info.ContainerStatsPercentiles, error) StatsSummary() (*info.ContainerStatsPercentiles, error)

View File

@ -285,12 +285,12 @@ func (self *dockerContainerHandler) GetStats() (stats *info.ContainerStats, err
return return
} }
func (self *dockerContainerHandler) ListContainers(listType container.ListType) ([]string, error) { func (self *dockerContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) {
if self.isDockerContainer() { if self.isDockerContainer() {
return nil, nil return nil, nil
} }
if self.isRootContainer() && listType == container.LIST_SELF { if self.isRootContainer() && listType == container.LIST_SELF {
return []string{"/docker"}, nil return []info.ContainerReference{info.ContainerReference{Name: "/docker"}}, nil
} }
opt := docker.ListContainersOptions{ opt := docker.ListContainersOptions{
All: true, All: true,
@ -299,16 +299,21 @@ func (self *dockerContainerHandler) ListContainers(listType container.ListType)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ret := make([]string, 0, len(containers)+1) ret := make([]info.ContainerReference, 0, len(containers)+1)
for _, c := range containers { for _, c := range containers {
if !strings.HasPrefix(c.Status, "Up ") { if !strings.HasPrefix(c.Status, "Up ") {
continue continue
} }
path := fmt.Sprintf("/docker/%v", c.ID) 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() { if self.isRootContainer() {
ret = append(ret, "/docker") ret = append(ret, info.ContainerReference{Name: "/docker"})
} }
return ret, nil return ret, nil
} }

View File

@ -34,7 +34,7 @@ func (self *containerListFilter) GetStats() (*info.ContainerStats, error) {
return self.handler.GetStats() 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) containers, err := self.handler.ListContainers(listType)
if err != nil { if err != nil {
return nil, err return nil, err
@ -42,9 +42,9 @@ func (self *containerListFilter) ListContainers(listType ListType) ([]string, er
if len(containers) == 0 { if len(containers) == 0 {
return nil, nil return nil, nil
} }
ret := make([]string, 0, len(containers)) ret := make([]info.ContainerReference, 0, len(containers))
for _, c := range containers { for _, c := range containers {
if self.filter(c) { if self.filter(c.Name) {
ret = append(ret, c) ret = append(ret, c)
} }
} }

View File

@ -37,9 +37,9 @@ func (self *mockContainerHandler) GetStats() (*info.ContainerStats, error) {
return args.Get(0).(*info.ContainerStats), args.Error(1) 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) 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) { 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) { func TestWhiteListContainerFilter(t *testing.T) {
mockc := &mockContainerHandler{} mockc := &mockContainerHandler{}
mockc.On("ListContainers", LIST_RECURSIVE).Return( mockc.On("ListContainers", LIST_RECURSIVE).Return(
[]string{ []info.ContainerReference{
"/docker/ee0103", info.ContainerReference{Name: "/docker/ee0103"},
"/container/created/by/lmctfy", info.ContainerReference{Name: "/container/created/by/lmctfy"},
"/user/something", info.ContainerReference{Name: "/user/something"},
}, },
nil, nil,
) )
@ -76,7 +76,7 @@ func TestWhiteListContainerFilter(t *testing.T) {
for _, c := range containers { for _, c := range containers {
legal := false legal := false
for _, prefix := range filterPaths { for _, prefix := range filterPaths {
if strings.HasPrefix(c, prefix) { if strings.HasPrefix(c.Name, prefix) {
legal = true legal = true
} }
} }
@ -90,10 +90,10 @@ func TestWhiteListContainerFilter(t *testing.T) {
func TestBlackListContainerFilter(t *testing.T) { func TestBlackListContainerFilter(t *testing.T) {
mockc := &mockContainerHandler{} mockc := &mockContainerHandler{}
mockc.On("ListContainers", LIST_RECURSIVE).Return( mockc.On("ListContainers", LIST_RECURSIVE).Return(
[]string{ []info.ContainerReference{
"/docker/ee0103", info.ContainerReference{Name: "/docker/ee0103"},
"/container/created/by/lmctfy", info.ContainerReference{Name: "/container/created/by/lmctfy"},
"/user/something", info.ContainerReference{Name: "/user/something"},
}, },
nil, nil,
) )
@ -111,7 +111,7 @@ func TestBlackListContainerFilter(t *testing.T) {
for _, c := range containers { for _, c := range containers {
legal := true legal := true
for _, prefix := range filterPaths { for _, prefix := range filterPaths {
if strings.HasPrefix(c, prefix) { if strings.HasPrefix(c.Name, prefix) {
legal = false legal = false
} }
} }

View File

@ -157,7 +157,7 @@ func (c *lmctfyContainerHandler) GetStats() (*info.ContainerStats, error) {
} }
// Gets all subcontainers. // 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. // Prepare the arguments.
args := []string{"list", "containers", "-v"} args := []string{"list", "containers", "-v"}
if listType == container.LIST_RECURSIVE { if listType == container.LIST_RECURSIVE {
@ -174,13 +174,14 @@ func (c *lmctfyContainerHandler) ListContainers(listType container.ListType) ([]
// Parse lines as container names. // Parse lines as container names.
if len(data) == 0 { if len(data) == 0 {
return []string{}, nil return nil, nil
} }
names := strings.Split(string(data), "\n") names := strings.Split(string(data), "\n")
containerNames := make([]string, 0, len(names)) containerNames := make([]info.ContainerReference, 0, len(names))
for _, name := range names { for _, name := range names {
if len(name) != 0 { if len(name) != 0 {
containerNames = append(containerNames, name) ref := info.ContainerReference{Name: name}
containerNames = append(containerNames, ref)
} }
} }
return containerNames, nil return containerNames, nil

View File

@ -94,7 +94,7 @@ func (self *percentilesContainerHandlerWrapper) GetStats() (*info.ContainerStats
return stats, nil 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) return self.handler.ListContainers(listType)
} }

View File

@ -29,7 +29,7 @@ type mockContainer struct {
func (self *mockContainer) GetSpec() (*info.ContainerSpec, error) { func (self *mockContainer) GetSpec() (*info.ContainerSpec, error) {
return nil, nil return nil, nil
} }
func (self *mockContainer) ListContainers(listType ListType) ([]string, error) { func (self *mockContainer) ListContainers(listType ListType) ([]info.ContainerReference, error) {
return nil, nil return nil, nil
} }

View File

@ -49,12 +49,19 @@ type ContainerSpec struct {
Memory *MemorySpec `json:"memory,omitempty"` 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. // The absolute name of the container.
Name string `json:"name"` Name string `json:"name"`
Aliases []string `json:"aliases,omitempty"`
}
type ContainerInfo struct {
ContainerReference
// The direct subcontainers of the current container. // The direct subcontainers of the current container.
Subcontainers []string `json:"subcontainers,omitempty"` Subcontainers []ContainerReference `json:"subcontainers,omitempty"`
// The isolation used in the container. // The isolation used in the container.
Spec *ContainerSpec `json:"spec,omitempty"` Spec *ContainerSpec `json:"spec,omitempty"`

View File

@ -30,7 +30,9 @@ func TestStatsStartTime(t *testing.T) {
stats = append(stats, s) stats = append(stats, s)
} }
cinfo := &ContainerInfo{ cinfo := &ContainerInfo{
Name: "/some/container", ContainerReference: ContainerReference{
Name: "/some/container",
},
Stats: stats, Stats: stats,
} }
ref := ct.Add(time.Duration(N-1) * time.Second) ref := ct.Add(time.Duration(N-1) * time.Second)
@ -52,7 +54,9 @@ func TestStatsEndTime(t *testing.T) {
stats = append(stats, s) stats = append(stats, s)
} }
cinfo := &ContainerInfo{ cinfo := &ContainerInfo{
Name: "/some/container", ContainerReference: ContainerReference{
Name: "/some/container",
},
Stats: stats, Stats: stats,
} }
ref := ct ref := ct

View File

@ -35,11 +35,11 @@ type containerStat struct {
Data *info.ContainerStats Data *info.ContainerStats
} }
type containerInfo struct { type containerInfo struct {
Name string info.ContainerReference
Subcontainers []string Subcontainers []info.ContainerReference
Spec *info.ContainerSpec Spec *info.ContainerSpec
Stats *list.List Stats *list.List
StatsSummary *info.ContainerStatsPercentiles StatsSummary *info.ContainerStatsPercentiles
} }
type containerData struct { type containerData struct {

View File

@ -111,7 +111,9 @@ func (m *manager) GetContainerInfo(containerName string) (*info.ContainerInfo, e
// Make a copy of the info for the user. // Make a copy of the info for the user.
ret := &info.ContainerInfo{ ret := &info.ContainerInfo{
Name: cinfo.Name, ContainerReference: info.ContainerReference{
Name: cinfo.Name,
},
Subcontainers: cinfo.Subcontainers, Subcontainers: cinfo.Subcontainers,
Spec: cinfo.Spec, Spec: cinfo.Spec,
StatsSummary: cinfo.StatsSummary, StatsSummary: cinfo.StatsSummary,
@ -180,10 +182,8 @@ func (m *manager) destroyContainer(containerName string) error {
return nil return nil
} }
type empty struct{}
// Detect all containers that have been added or deleted. // 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. // TODO(vmarmol): We probably don't need to lock around / since it will always be there.
m.containersLock.RLock() m.containersLock.RLock()
defer m.containersLock.RUnlock() defer m.containersLock.RUnlock()
@ -197,24 +197,24 @@ func (m *manager) getContainersDiff() (added []string, removed []string, err err
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
allContainers = append(allContainers, "/") allContainers = append(allContainers, info.ContainerReference{Name: "/"})
// Determine which were added and which were removed. // Determine which were added and which were removed.
allContainersSet := make(map[string]*empty) allContainersSet := make(map[string]*containerData)
for name, _ := range m.containers { for name, d := range m.containers {
allContainersSet[name] = &empty{} allContainersSet[name] = d
} }
for _, name := range allContainers { for _, c := range allContainers {
delete(allContainersSet, name) delete(allContainersSet, c.Name)
_, ok := m.containers[name] _, ok := m.containers[c.Name]
if !ok { if !ok {
added = append(added, name) added = append(added, c)
} }
} }
// Removed ones are no longer in the container listing. // Removed ones are no longer in the container listing.
for name, _ := range allContainersSet { for _, d := range allContainersSet {
removed = append(removed, name) removed = append(removed, d.info.ContainerReference)
} }
return return
@ -228,18 +228,18 @@ func (m *manager) detectContainers() error {
} }
// Add the new containers. // Add the new containers.
for _, name := range added { for _, container := range added {
_, err = m.createContainer(name) _, err = m.createContainer(container.Name)
if err != nil { 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. // Remove the old containers.
for _, name := range removed { for _, container := range removed {
err = m.destroyContainer(name) err = m.destroyContainer(container.Name)
if err != nil { 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)
} }
} }

View File

@ -50,8 +50,8 @@ var pageTemplate *template.Template
type pageData struct { type pageData struct {
ContainerName string ContainerName string
ParentContainers []string ParentContainers []info.ContainerReference
Subcontainers []string Subcontainers []info.ContainerReference
Spec *info.ContainerSpec Spec *info.ContainerSpec
Stats []*info.ContainerStats Stats []*info.ContainerStats
MachineInfo *info.MachineInfo MachineInfo *info.MachineInfo
@ -69,14 +69,17 @@ func init() {
} }
// TODO(vmarmol): Escape this correctly. // 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 var displayName string
if basenameOnly { containerName := container.Name
displayName = path.Base(string(containerName)) if len(container.Aliases) > 0 {
displayName = container.Aliases[0]
} else if basenameOnly {
displayName = path.Base(string(container.Name))
} else { } else {
displayName = string(containerName) displayName = string(container.Name)
} }
if containerName == "root" { if container.Name == "root" {
containerName = "/" containerName = "/"
} }
return template.HTML(fmt.Sprintf("<a class=\"%s\" href=\"%s%s\">%s</a>", cssClasses, ContainersPage[:len(ContainersPage)-1], containerName, displayName)) return template.HTML(fmt.Sprintf("<a class=\"%s\" href=\"%s%s\">%s</a>", 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 // Make a list of the parent containers and their links
var parentContainers []string var parentContainers []info.ContainerReference
parentContainers = append(parentContainers, string("root")) parentContainers = append(parentContainers, info.ContainerReference{Name: "root"})
parentName := "" parentName := ""
for _, part := range strings.Split(string(cont.Name), "/") { for _, part := range strings.Split(string(cont.Name), "/") {
if part == "" { if part == "" {
continue continue
} }
parentName += "/" + part parentName += "/" + part
parentContainers = append(parentContainers, string(parentName)) parentContainers = append(parentContainers, info.ContainerReference{Name: parentName})
} }
data := &pageData{ data := &pageData{