diff --git a/cadvisor.go b/cadvisor.go index bf499ea8..dec93e61 100644 --- a/cadvisor.go +++ b/cadvisor.go @@ -63,12 +63,12 @@ func main() { // Register the raw driver. if err := raw.Register(containerManager); err != nil { - glog.Fatalf("raw registration failed: %v.", err) + glog.Fatalf("Raw registration failed: %v.", err) } // Basic health handler. if err := healthz.RegisterHandler(); err != nil { - glog.Fatalf("failed to register healthz handler: %s", err) + glog.Fatalf("Failed to register healthz handler: %s", err) } // Handler for static content. @@ -81,19 +81,15 @@ func main() { // Register API handler. if err := api.RegisterHandlers(containerManager); err != nil { - glog.Fatalf("failed to register API handlers: %s", err) + glog.Fatalf("Failed to register API handlers: %s", err) } // Redirect / to containers page. http.Handle("/", http.RedirectHandler(pages.ContainersPage, http.StatusTemporaryRedirect)) - // Register the handler for the containers page. - http.HandleFunc(pages.ContainersPage, func(w http.ResponseWriter, r *http.Request) { - err := pages.ServerContainersPage(containerManager, w, r.URL) - if err != nil { - fmt.Fprintf(w, "%s", err) - } - }) + if err := pages.RegisterHandlers(containerManager); err != nil { + glog.Fatalf("Failed to register pages handlers: %s", err) + } // Start the manager. if err := containerManager.Start(); err != nil { diff --git a/container/docker/factory.go b/container/docker/factory.go index 65a3a7a4..e46ad850 100644 --- a/container/docker/factory.go +++ b/container/docker/factory.go @@ -82,6 +82,26 @@ func IsDockerContainerName(name string) bool { } } +// Returns the Docker ID from the full container name. +func ContainerNameToDockerId(name string) string { + id := path.Base(name) + + // Turn systemd cgroup name into Docker ID. + if useSystemd { + const systemdDockerPrefix = "docker-" + if strings.HasPrefix(id, systemdDockerPrefix) { + id = id[len(systemdDockerPrefix):] + } + + const systemdScopeSuffix = ".scope" + if strings.HasSuffix(id, systemdScopeSuffix) { + id = id[:len(id)-len(systemdScopeSuffix)] + } + } + + return id +} + // Returns a list of possible full container names for the specified Docker container name. func FullDockerContainerNames(dockerName string) []string { names := make([]string, 0, 2) @@ -107,7 +127,7 @@ func (self *dockerFactory) CanHandle(name string) (bool, error) { } // Check if the container is known to docker and it is active. - id := containerNameToDockerId(name) + id := ContainerNameToDockerId(name) // We assume that if Inspect fails then the container is not known to docker. ctnr, err := self.client.InspectContainer(id) diff --git a/container/docker/handler.go b/container/docker/handler.go index 968b40e0..e3d8ee4e 100644 --- a/container/docker/handler.go +++ b/container/docker/handler.go @@ -85,7 +85,7 @@ func newDockerContainerHandler( if handler.isDockerRoot() { return handler, nil } - id := containerNameToDockerId(name) + id := ContainerNameToDockerId(name) handler.id = id ctnr, err := client.InspectContainer(id) // We assume that if Inspect fails then the container is not known to docker. @@ -96,25 +96,6 @@ func newDockerContainerHandler( return handler, nil } -func containerNameToDockerId(name string) string { - id := path.Base(name) - - // Turn systemd cgroup name into Docker ID. - if useSystemd { - const systemdDockerPrefix = "docker-" - if strings.HasPrefix(id, systemdDockerPrefix) { - id = id[len(systemdDockerPrefix):] - } - - const systemdScopeSuffix = ".scope" - if strings.HasSuffix(id, systemdScopeSuffix) { - id = id[:len(id)-len(systemdScopeSuffix)] - } - } - - return id -} - func (self *dockerContainerHandler) ContainerReference() (info.ContainerReference, error) { return info.ContainerReference{ Name: self.name, diff --git a/pages/containers.go b/pages/containers.go index d6ceb04c..4b6d707b 100644 --- a/pages/containers.go +++ b/pages/containers.go @@ -88,7 +88,6 @@ func (b ByteSize) Unit() string { } var funcMap = template.FuncMap{ - "containerLink": containerLink, "printMask": printMask, "printCores": printCores, "printShares": printShares, @@ -102,52 +101,6 @@ var funcMap = template.FuncMap{ "getFsUsagePercent": getFsUsagePercent, } -// TODO(vmarmol): Consider housekeeping Spec too so we can show changes through time. We probably don't need it ever second though. - -var pageTemplate *template.Template - -type pageData struct { - ContainerName string - ParentContainers []info.ContainerReference - Subcontainers []info.ContainerReference - Spec info.ContainerSpec - Stats []*info.ContainerStats - MachineInfo *info.MachineInfo - ResourcesAvailable bool - CpuAvailable bool - MemoryAvailable bool - NetworkAvailable bool - FsAvailable bool -} - -func init() { - pageTemplate = template.New("containersTemplate").Funcs(funcMap) - _, err := pageTemplate.Parse(containersHtmlTemplate) - if err != nil { - glog.Fatalf("Failed to parse template: %s", err) - } -} - -// TODO(vmarmol): Escape this correctly. -func containerLink(container info.ContainerReference, basenameOnly bool, cssClasses string) interface{} { - var displayName string - containerName := container.Name - if len(container.Aliases) > 0 { - displayName = container.Aliases[0] - } else if basenameOnly { - displayName = path.Base(string(container.Name)) - } else { - displayName = string(container.Name) - } - if container.Name == "root" { - containerName = "/" - } else if strings.Contains(container.Name, " ") { - // If it has a space, it is an a.k.a, so keep the base-name - containerName = container.Name[:strings.Index(container.Name, " ")] - } - return template.HTML(fmt.Sprintf("%s", cssClasses, ContainersPage[:len(ContainersPage)-1], containerName, displayName)) -} - func printMask(mask string, numCores int) interface{} { masks := make([]string, numCores) activeCores := getActiveCores(mask) @@ -266,7 +219,7 @@ func getFsUsagePercent(limit, used uint64) uint64 { return uint64((float64(used) / float64(limit)) * 100) } -func ServerContainersPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error { +func serveContainersPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error { start := time.Now() // The container name is the path after the handler @@ -278,8 +231,9 @@ func ServerContainersPage(m manager.Manager, w http.ResponseWriter, u *url.URL) } cont, err := m.GetContainerInfo(containerName, &reqParams) if err != nil { - return fmt.Errorf("Failed to get container \"%s\" with error: %s", containerName, err) + return fmt.Errorf("Failed to get container %q with error: %v", containerName, err) } + displayName := getContainerDisplayName(cont.ContainerReference) // Get the MachineInfo machineInfo, err := m.GetMachineInfo() @@ -288,41 +242,41 @@ func ServerContainersPage(m manager.Manager, w http.ResponseWriter, u *url.URL) } // Make a list of the parent containers and their links - var parentContainers []info.ContainerReference - parentContainers = append(parentContainers, info.ContainerReference{Name: "root"}) - parentName := "" - for _, part := range strings.Split(string(cont.Name), "/") { - if part == "" { + pathParts := strings.Split(string(cont.Name), "/") + parentContainers := make([]link, 0, len(pathParts)) + parentContainers = append(parentContainers, link{ + Text: "root", + Link: ContainersPage, + }) + for i := 1; i < len(pathParts); i++ { + // Skip empty parts. + if pathParts[i] == "" { continue } - parentName += "/" + part - parentContainers = append(parentContainers, info.ContainerReference{Name: parentName}) + parentContainers = append(parentContainers, link{ + Text: pathParts[i], + Link: path.Join(ContainersPage, path.Join(pathParts[1:i+1]...)), + }) } - // Pick the shortest name of the container as the display name. - displayName := cont.Name - for _, alias := range cont.Aliases { - if len(displayName) >= len(alias) { - displayName = alias - } - } - - // Replace the last part of the parent containers with the displayName. - if displayName != cont.Name { - parentContainers[len(parentContainers)-1] = info.ContainerReference{ - Name: fmt.Sprintf("%s (%s)", displayName, path.Base(cont.Name)), - } + // Build the links for the subcontainers. + subcontainerLinks := make([]link, 0, len(cont.Subcontainers)) + for _, sub := range cont.Subcontainers { + subcontainerLinks = append(subcontainerLinks, link{ + Text: getContainerDisplayName(sub), + Link: path.Join(ContainersPage, sub.Name), + }) } data := &pageData{ - ContainerName: displayName, - // TODO(vmarmol): Only use strings for this. + DisplayName: displayName, + ContainerName: cont.Name, ParentContainers: parentContainers, - Subcontainers: cont.Subcontainers, + Subcontainers: subcontainerLinks, Spec: cont.Spec, Stats: cont.Stats, MachineInfo: machineInfo, - ResourcesAvailable: cont.Spec.HasCpu || cont.Spec.HasMemory || cont.Spec.HasNetwork, + ResourcesAvailable: cont.Spec.HasCpu || cont.Spec.HasMemory || cont.Spec.HasNetwork || cont.Spec.HasFilesystem, CpuAvailable: cont.Spec.HasCpu, MemoryAvailable: cont.Spec.HasMemory, NetworkAvailable: cont.Spec.HasNetwork, diff --git a/pages/containers_html.go b/pages/containers_html.go index d3d0979d..6ca2406c 100644 --- a/pages/containers_html.go +++ b/pages/containers_html.go @@ -17,7 +17,7 @@ package pages const containersHtmlTemplate = `
-