func streamResults(eventChannel *events.EventChannel, w http.ResponseWriter, r *http.Request, m manager.Manager) error { cn, ok := w.(http.CloseNotifier) if !ok { return errors.New("could not access http.CloseNotifier") } flusher, ok := w.(http.Flusher) if !ok { return errors.New("could not access http.Flusher") } w.Header().Set("Transfer-Encoding", "chunked") w.WriteHeader(http.StatusOK) flusher.Flush() enc := json.NewEncoder(w) for { select { case <-cn.CloseNotify(): m.CloseEventChannel(eventChannel.GetWatchId()) return nil case ev := <-eventChannel.GetChannel(): err := enc.Encode(ev) if err != nil { glog.Errorf("error encoding message %+v for result stream: %v", ev, err) } flusher.Flush() } } }
func (self *version1_3) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { switch requestType { case eventsApi: query, eventsFromAllTime, err := getEventRequest(r) if err != nil { return err } glog.V(2).Infof("Api - Events(%v)", query) if eventsFromAllTime { pastEvents, err := m.GetPastEvents(query) if err != nil { return err } return writeResult(pastEvents, w) } eventsChannel := make(chan *events.Event, 10) err = m.WatchForEvents(query, eventsChannel) if err != nil { return err } return streamResults(eventsChannel, w, r) default: return self.baseVersion.HandleRequest(requestType, request, m, w, r) } }
func HandleRequest(w http.ResponseWriter, containerManager manager.Manager) error { // Get cAdvisor version Info. versionInfo, err := containerManager.GetVersionInfo() if err != nil { return err } out := fmt.Sprintf("cAdvisor version: %s\n\n", versionInfo.CadvisorVersion) // No OS is preferred or unsupported as of now. out += fmt.Sprintf("OS version: %s\n\n", versionInfo.ContainerOsVersion) kernelValidation, desc := validateKernelVersion(versionInfo.KernelVersion) out += fmt.Sprintf(OutputFormat, "Kernel version", kernelValidation, desc) cgroupValidation, desc := validateCgroups() out += fmt.Sprintf(OutputFormat, "Cgroup setup", cgroupValidation, desc) mountsValidation, desc := validateCgroupMounts() out += fmt.Sprintf(OutputFormat, "Cgroup mount setup", mountsValidation, desc) dockerValidation, desc := validateDockerVersion(versionInfo.DockerVersion) out += fmt.Sprintf(OutputFormat, "Docker version", dockerValidation, desc) dockerInfoValidation, desc := validateDockerInfo() out += fmt.Sprintf(OutputFormat, "Docker driver setup", dockerInfoValidation, desc) ioSchedulerValidation, desc := validateIoScheduler(containerManager) out += fmt.Sprintf(OutputFormat, "Block device setup", ioSchedulerValidation, desc) _, err = w.Write([]byte(out)) return err }
func (self *version1_1) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { switch requestType { case subcontainersApi: containerName := getContainerName(request) glog.V(4).Infof("Api - Subcontainers(%s)", containerName) // Get the query request. query, err := getContainerInfoRequest(r.Body) if err != nil { return err } // Get the subcontainers. containers, err := m.SubcontainersInfo(containerName, query) if err != nil { return fmt.Errorf("failed to get subcontainers for container %q with error: %s", containerName, err) } // Only output the containers as JSON. err = writeResult(containers, w) if err != nil { return err } return nil default: return self.baseVersion.HandleRequest(requestType, request, m, w, r) } }
func (self *version2_1) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { // Get the query request. opt, err := getRequestOptions(r) if err != nil { return err } switch requestType { case machineStatsApi: glog.V(4).Infof("Api - MachineStats(%v)", request) cont, err := m.GetRequestedContainersInfo("/", opt) if err != nil { return err } return writeResult(v2.MachineStatsFromV1(cont["/"]), w) case statsApi: name := getContainerName(request) glog.V(4).Infof("Api - Stats: Looking for stats for container %q, options %+v", name, opt) conts, err := m.GetRequestedContainersInfo(name, opt) if err != nil { return err } contStats := make(map[string][]*v2.ContainerStats, len(conts)) for name, cont := range conts { contStats[name] = v2.ContainerStatsFromV1(&cont.Spec, cont.Stats) } return writeResult(contStats, w) default: return self.baseVersion.HandleRequest(requestType, request, m, w, r) } }
func (self *version2_0) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { switch requestType { case summaryApi: containerName := getContainerName(request) glog.V(2).Infof("Api - Summary(%v)", containerName) stats, err := m.GetContainerDerivedStats(containerName) if err != nil { return err } return writeResult(stats, w) case statsApi: name := getContainerName(request) sr, err := getStatsRequest(name, r) if err != nil { return err } glog.V(2).Infof("Api - Stats: Looking for stats for container %q, options %+v", name, sr) query := info.ContainerInfoRequest{ NumStats: sr.Count, } cont, err := m.GetContainerInfo(name, &query) if err != nil { return fmt.Errorf("failed to get container %q: %v", name, err) } contStats := convertStats(cont) return writeResult(contStats, w) case specApi: containerName := getContainerName(request) glog.V(2).Infof("Api - Spec(%v)", containerName) spec, err := m.GetContainerSpec(containerName) if err != nil { return err } specV2 := convertSpec(spec) return writeResult(specV2, w) case storageApi: var err error fi := []v2.FsInfo{} label := r.URL.Query().Get("label") if len(label) == 0 { // Get all global filesystems info. fi, err = m.GetFsInfo("") if err != nil { return err } } else { // Get a specific label. fi, err = m.GetFsInfo(label) if err != nil { return err } } return writeResult(fi, w) default: return self.baseVersion.HandleRequest(requestType, request, m, w, r) } }
func HandleRequest(m manager.Manager, w http.ResponseWriter, u *url.URL) error { start := time.Now() // Get API request type. requestType := u.Path[len(ApiResource):] i := strings.Index(requestType, "/") requestArgs := "" if i != -1 { requestArgs = requestType[i:] requestType = requestType[:i] } if requestType == MachineApi { log.Printf("Api - Machine") // Get the MachineInfo machineInfo, err := m.GetMachineInfo() if err != nil { return err } out, err := json.Marshal(machineInfo) if err != nil { fmt.Fprintf(w, "Failed to marshall MachineInfo with error: %s", err) } w.Write(out) } else if requestType == ContainersApi { // The container name is the path after the requestType containerName := requestArgs log.Printf("Api - Container(%s)", containerName) // Get the container. cont, err := m.GetContainerInfo(containerName) if err != nil { fmt.Fprintf(w, "Failed to get container \"%s\" with error: %s", containerName, err) return err } // Only output the container as JSON. out, err := json.Marshal(cont) if err != nil { fmt.Fprintf(w, "Failed to marshall container %q with error: %s", containerName, err) } w.Write(out) } else { return fmt.Errorf("unknown API request type %q", requestType) } log.Printf("Request took %s", time.Since(start)) return nil }
func installSignalHandler(containerManager manager.Manager) { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGTERM) // Block until a signal is received. go func() { sig := <-c if err := containerManager.Stop(); err != nil { glog.Errorf("Failed to stop container manager: %v", err) } glog.Infof("Exiting given signal: %v", sig) os.Exit(0) }() }
func (self *version1_3) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { switch requestType { case eventsApi: return handleEventRequest(request, m, w, r) case hyperApi: glog.V(4).Infof("Api - Hyper(%v)", request) // Get the query request. query, err := getContainerInfoRequest(r.Body) if err != nil { return err } var containers map[string]info.ContainerInfo // map requests for "hyper/" to "hyper" if len(request) == 1 && len(request[0]) == 0 { request = request[:0] } switch len(request) { case 0: // Get all Hyper pods. containers, err = m.AllHyperContainers(query) if err != nil { return fmt.Errorf("failed to get all Hyper pods with error: %v", err) } case 1: // Get one Hyper pod. var cont info.ContainerInfo cont, err = m.HyperContainer(request[0], query) if err != nil { return fmt.Errorf("failed to get Docker container %q with error: %v", request[0], err) } containers = map[string]info.ContainerInfo{ cont.Name: cont, } default: return fmt.Errorf("unknown request for Docker container %v", request) } // Only output the containers as JSON. err = writeResult(containers, w) if err != nil { return err } return nil default: return self.baseVersion.HandleRequest(requestType, request, m, w, r) } }
func ServerContainersPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error { start := time.Now() // The container name is the path after the handler containerName := u.Path[len(ContainersPage)-1:] // Get the container. cont, err := m.GetContainerInfo(containerName) if err != nil { return fmt.Errorf("Failed to get container \"%s\" with error: %s", containerName, err) } // Get the MachineInfo machineInfo, err := m.GetMachineInfo() if err != nil { return err } // Make a list of the parent containers and their links var parentContainers []string parentContainers = append(parentContainers, string("root")) parentName := "" for _, part := range strings.Split(string(cont.Name), "/") { if part == "" { continue } parentName += "/" + part parentContainers = append(parentContainers, string(parentName)) } data := &pageData{ ContainerName: cont.Name, ParentContainers: parentContainers, Subcontainers: cont.Subcontainers, Spec: cont.Spec, Stats: cont.Stats, MachineInfo: machineInfo, ResourcesAvailable: cont.Spec.Cpu != nil || cont.Spec.Memory != nil, CpuAvailable: cont.Spec.Cpu != nil, MemoryAvailable: cont.Spec.Memory != nil, } err = pageTemplate.Execute(w, data) if err != nil { log.Printf("Failed to apply template: %s", err) } log.Printf("Request took %s", time.Since(start)) return nil }
func (self *version2_1) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { // Get the query request. opt, err := getRequestOptions(r) if err != nil { return err } switch requestType { case machineStatsApi: glog.V(4).Infof("Api - MachineStats(%v)", request) cont, err := m.GetRequestedContainersInfo("/", opt) if err != nil { if len(cont) == 0 { return err } glog.Errorf("Error calling GetRequestedContainersInfo: %v", err) } return writeResult(v2.MachineStatsFromV1(cont["/"]), w) case statsApi: name := getContainerName(request) glog.V(4).Infof("Api - Stats: Looking for stats for container %q, options %+v", name, opt) conts, err := m.GetRequestedContainersInfo(name, opt) if err != nil { if len(conts) == 0 { return err } glog.Errorf("Error calling GetRequestedContainersInfo: %v", err) } contStats := make(map[string]v2.ContainerInfo, len(conts)) for name, cont := range conts { if name == "/" { // Root cgroup stats should be exposed as machine stats continue } contStats[name] = v2.ContainerInfo{ Spec: v2.ContainerSpecFromV1(&cont.Spec, cont.Aliases, cont.Namespace), Stats: v2.ContainerStatsFromV1(&cont.Spec, cont.Stats), } } return writeResult(contStats, w) default: return self.baseVersion.HandleRequest(requestType, request, m, w, r) } }
func (self *version1_0) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { switch requestType { case machineApi: glog.V(4).Infof("Api - Machine") // Get the MachineInfo machineInfo, err := m.GetMachineInfo() if err != nil { return err } err = writeResult(machineInfo, w) if err != nil { return err } case containersApi: containerName := getContainerName(request) glog.V(4).Infof("Api - Container(%s)", containerName) // Get the query request. query, err := getContainerInfoRequest(r.Body) if err != nil { return err } // Get the container. cont, err := m.GetContainerInfo(containerName, query) if err != nil { return fmt.Errorf("failed to get container %q with error: %s", containerName, err) } // Only output the container as JSON. err = writeResult(cont, w) if err != nil { return err } default: return fmt.Errorf("unknown request type %q", requestType) } return nil }
func handleEventRequest(request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { query, stream, err := getEventRequest(r) if err != nil { return err } query.ContainerName = path.Join("/", getContainerName(request)) glog.V(4).Infof("Api - Events(%v)", query) if !stream { pastEvents, err := m.GetPastEvents(query) if err != nil { return err } return writeResult(pastEvents, w) } eventChannel, err := m.WatchForEvents(query) if err != nil { return err } return streamResults(eventChannel, w, r, m) }
func validateIoScheduler(containerManager manager.Manager) (string, string) { var desc string mi, err := containerManager.GetMachineInfo() if err != nil { return Unknown, "Machine info not available\n\t" } cfq := false for _, disk := range mi.DiskMap { desc += fmt.Sprintf("\t Disk %q Scheduler type %q.\n", disk.Name, disk.Scheduler) if disk.Scheduler == "cfq" { cfq = true } } // Since we get lot of random block devices, report recommended if // at least one of them is on cfq. Report Supported otherwise. if cfq { desc = "At least one device supports 'cfq' I/O scheduler. Some disk stats can be reported.\n" + desc return Recommended, desc } desc = "None of the devices support 'cfq' I/O scheduler. No disk stats can be reported.\n" + desc return Supported, desc }
func (self *version2_0) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { opt, err := getRequestOptions(r) if err != nil { return err } switch requestType { case versionApi: glog.V(4).Infof("Api - Version") versionInfo, err := m.GetVersionInfo() if err != nil { return err } return writeResult(versionInfo.CadvisorVersion, w) case attributesApi: glog.V(4).Info("Api - Attributes") machineInfo, err := m.GetMachineInfo() if err != nil { return err } versionInfo, err := m.GetVersionInfo() if err != nil { return err } info := v2.GetAttributes(machineInfo, versionInfo) return writeResult(info, w) case machineApi: glog.V(4).Info("Api - Machine") // TODO(rjnagal): Move machineInfo from v1. machineInfo, err := m.GetMachineInfo() if err != nil { return err } return writeResult(machineInfo, w) case summaryApi: containerName := getContainerName(request) glog.V(4).Infof("Api - Summary for container %q, options %+v", containerName, opt) stats, err := m.GetDerivedStats(containerName, opt) if err != nil { return err } return writeResult(stats, w) case statsApi: name := getContainerName(request) glog.V(4).Infof("Api - Stats: Looking for stats for container %q, options %+v", name, opt) conts, err := m.GetRequestedContainersInfo(name, opt) if err != nil { return err } contStats := make(map[string][]v2.ContainerStats, 0) for name, cont := range conts { contStats[name] = convertStats(cont) } return writeResult(contStats, w) case specApi: containerName := getContainerName(request) glog.V(4).Infof("Api - Spec for container %q, options %+v", containerName, opt) specs, err := m.GetContainerSpec(containerName, opt) if err != nil { return err } return writeResult(specs, w) case storageApi: var err error fi := []v2.FsInfo{} label := r.URL.Query().Get("label") if len(label) == 0 { // Get all global filesystems info. fi, err = m.GetFsInfo("") if err != nil { return err } } else { // Get a specific label. fi, err = m.GetFsInfo(label) if err != nil { return err } } return writeResult(fi, w) case eventsApi: return handleEventRequest(request, m, w, r) default: return fmt.Errorf("unknown request type %q", requestType) } }
func serveDockerPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error { start := time.Now() // The container name is the path after the handler containerName := u.Path[len(DockerPage):] rootDir := getRootDir(u.Path) var data *pageData if containerName == "" { // Get the containers. reqParams := info.ContainerInfoRequest{ NumStats: 0, } conts, err := m.AllDockerContainers(&reqParams) if err != nil { return fmt.Errorf("failed to get container %q with error: %v", containerName, err) } subcontainers := make([]link, 0, len(conts)) for _, cont := range conts { subcontainers = append(subcontainers, link{ Text: getContainerDisplayName(cont.ContainerReference), Link: path.Join("/docker", docker.ContainerNameToDockerId(cont.ContainerReference.Name)), }) } // Get Docker status status, err := m.DockerInfo() if err != nil { return err } dockerStatus, driverStatus := toStatusKV(status) // Get Docker Images images, err := m.DockerImages() if err != nil { return err } dockerContainersText := "Docker Containers" data = &pageData{ DisplayName: dockerContainersText, ParentContainers: []link{ { Text: dockerContainersText, Link: DockerPage, }}, Subcontainers: subcontainers, Root: rootDir, DockerStatus: dockerStatus, DockerDriverStatus: driverStatus, DockerImages: images, } } else { // Get the container. reqParams := info.ContainerInfoRequest{ NumStats: 60, } cont, err := m.DockerContainer(containerName, &reqParams) if err != nil { return fmt.Errorf("failed to get container %q with error: %v", containerName, err) } displayName := getContainerDisplayName(cont.ContainerReference) // Make a list of the parent containers and their links var parentContainers []link parentContainers = append(parentContainers, link{ Text: "Docker containers", Link: DockerPage, }) parentContainers = append(parentContainers, link{ Text: displayName, Link: path.Join(DockerPage, docker.ContainerNameToDockerId(cont.Name)), }) // Get the MachineInfo machineInfo, err := m.GetMachineInfo() if err != nil { return err } data = &pageData{ DisplayName: displayName, ContainerName: cont.Name, ParentContainers: parentContainers, Spec: cont.Spec, Stats: cont.Stats, MachineInfo: machineInfo, ResourcesAvailable: cont.Spec.HasCpu || cont.Spec.HasMemory || cont.Spec.HasNetwork, CpuAvailable: cont.Spec.HasCpu, MemoryAvailable: cont.Spec.HasMemory, NetworkAvailable: cont.Spec.HasNetwork, FsAvailable: cont.Spec.HasFilesystem, Root: rootDir, } } err := pageTemplate.Execute(w, data) if err != nil { glog.Errorf("Failed to apply template: %s", err) } glog.V(5).Infof("Request took %s", time.Since(start)) return nil }
func ServerContainersPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error { start := time.Now() // The container name is the path after the handler containerName := u.Path[len(ContainersPage)-1:] // Get the container. reqParams := info.ContainerInfoRequest{ NumStats: 60, NumSamples: 60, } cont, err := m.GetContainerInfo(containerName, &reqParams) if err != nil { return fmt.Errorf("Failed to get container \"%s\" with error: %s", containerName, err) } // Get the MachineInfo machineInfo, err := m.GetMachineInfo() if err != nil { return err } // 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 == "" { continue } parentName += "/" + part parentContainers = append(parentContainers, info.ContainerReference{Name: parentName}) } // 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)), } } data := &pageData{ ContainerName: displayName, // TODO(vmarmol): Only use strings for this. ParentContainers: parentContainers, Subcontainers: cont.Subcontainers, Spec: cont.Spec, Stats: cont.Stats, MachineInfo: machineInfo, ResourcesAvailable: cont.Spec.Cpu != nil || cont.Spec.Memory != nil, CpuAvailable: cont.Spec.Cpu != nil, MemoryAvailable: cont.Spec.Memory != nil, } err = pageTemplate.Execute(w, data) if err != nil { log.Printf("Failed to apply template: %s", err) } log.Printf("Request took %s", time.Since(start)) return nil }
func handleRequest(m manager.Manager, w http.ResponseWriter, r *http.Request) error { start := time.Now() request := r.URL.Path requestElements := strings.Split(r.URL.Path, "/") // Verify that we have all the elements we expect: // <empty>/api/<version>/<request type>[/<args...>] // [0] [1] [2] [3] [4...] if len(requestElements) < 4 { return fmt.Errorf("incomplete API request %q", request) } // Get all the element parts. emptyElement := requestElements[0] apiElement := requestElements[1] version := requestElements[2] requestType := requestElements[3] requestArgs := []string{} if len(requestElements) > 4 { requestArgs = requestElements[4:] } // The container name is the path after the requestType. containerName := path.Join("/", strings.Join(requestArgs, "/")) // Check elements. if len(emptyElement) != 0 { return fmt.Errorf("unexpected API request format %q", request) } if apiElement != "api" { return fmt.Errorf("invalid API request format %q", request) } if _, ok := supportedApiVersions[version]; !ok { return fmt.Errorf("unsupported API version %q", version) } switch { case requestType == machineApi: glog.V(2).Infof("Api - Machine") // Get the MachineInfo machineInfo, err := m.GetMachineInfo() if err != nil { return err } err = writeResult(machineInfo, w) if err != nil { return err } case requestType == containersApi: glog.V(2).Infof("Api - Container(%s)", containerName) // Get the query request. query, err := getContainerInfoRequest(r.Body) if err != nil { return err } // Get the container. cont, err := m.GetContainerInfo(containerName, query) if err != nil { return fmt.Errorf("failed to get container %q with error: %s", containerName, err) } // Only output the container as JSON. err = writeResult(cont, w) if err != nil { return err } case requestType == subcontainersApi: if version == version1_0 { return fmt.Errorf("request type of %q not supported in API version %q", requestType, version) } glog.V(2).Infof("Api - Subcontainers(%s)", containerName) // Get the query request. query, err := getContainerInfoRequest(r.Body) if err != nil { return err } // Get the subcontainers. containers, err := m.SubcontainersInfo(containerName, query) if err != nil { return fmt.Errorf("failed to get subcontainers for container %q with error: %s", containerName, err) } // Only output the containers as JSON. err = writeResult(containers, w) if err != nil { return err } case requestType == dockerApi: if version == version1_0 || version == version1_1 { return fmt.Errorf("request type of %q not supported in API version %q", requestType, version) } glog.V(2).Infof("Api - Docker(%s)", containerName) // Get the query request. query, err := getContainerInfoRequest(r.Body) if err != nil { return err } // Get the Docker containers. containers, err := m.DockerContainersInfo(containerName, query) if err != nil { return fmt.Errorf("failed to get docker containers for %q with error: %s", containerName, err) } // Only output the containers as JSON. err = writeResult(containers, w) if err != nil { return err } default: return fmt.Errorf("unknown API request type %q", requestType) } glog.V(2).Infof("Request took %s", time.Since(start)) return nil }
func (self *version2_0) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { opt, err := getRequestOptions(r) if err != nil { return err } switch requestType { case versionApi: glog.V(4).Infof("Api - Version") versionInfo, err := m.GetVersionInfo() if err != nil { return err } return writeResult(versionInfo.CadvisorVersion, w) case attributesApi: glog.V(4).Info("Api - Attributes") machineInfo, err := m.GetMachineInfo() if err != nil { return err } versionInfo, err := m.GetVersionInfo() if err != nil { return err } info := v2.GetAttributes(machineInfo, versionInfo) return writeResult(info, w) case machineApi: glog.V(4).Info("Api - Machine") // TODO(rjnagal): Move machineInfo from v1. machineInfo, err := m.GetMachineInfo() if err != nil { return err } return writeResult(machineInfo, w) case summaryApi: containerName := getContainerName(request) glog.V(4).Infof("Api - Summary for container %q, options %+v", containerName, opt) stats, err := m.GetDerivedStats(containerName, opt) if err != nil { return err } return writeResult(stats, w) case statsApi: name := getContainerName(request) glog.V(4).Infof("Api - Stats: Looking for stats for container %q, options %+v", name, opt) conts, err := m.GetRequestedContainersInfo(name, opt) if err != nil { return err } contStats := make(map[string][]v2.ContainerStats, 0) for name, cont := range conts { contStats[name] = convertStats(cont) } return writeResult(contStats, w) case customMetricsApi: containerName := getContainerName(request) glog.V(4).Infof("Api - Custom Metrics: Looking for metrics for container %q, options %+v", containerName, opt) conts, err := m.GetRequestedContainersInfo(containerName, opt) if err != nil { return err } contMetrics := make(map[string]map[string]map[string][]info.MetricValBasic, 0) for _, cont := range conts { metrics := make(map[string]map[string][]info.MetricValBasic, 0) contStats := convertStats(cont) for _, contStat := range contStats { if contStat.HasCustomMetrics { for name, allLabels := range contStat.CustomMetrics { metricLabels := make(map[string][]info.MetricValBasic, 0) for _, metric := range allLabels { if !metric.Timestamp.IsZero() { metVal := info.MetricValBasic{ Timestamp: metric.Timestamp, IntValue: metric.IntValue, FloatValue: metric.FloatValue, } labels := metrics[name] if labels != nil { values := labels[metric.Label] values = append(values, metVal) labels[metric.Label] = values metrics[name] = labels } else { metricLabels[metric.Label] = []info.MetricValBasic{metVal} metrics[name] = metricLabels } } } } } } contMetrics[containerName] = metrics } return writeResult(contMetrics, w) case specApi: containerName := getContainerName(request) glog.V(4).Infof("Api - Spec for container %q, options %+v", containerName, opt) specs, err := m.GetContainerSpec(containerName, opt) if err != nil { return err } return writeResult(specs, w) case storageApi: var err error fi := []v2.FsInfo{} label := r.URL.Query().Get("label") if len(label) == 0 { // Get all global filesystems info. fi, err = m.GetFsInfo("") if err != nil { return err } } else { // Get a specific label. fi, err = m.GetFsInfo(label) if err != nil { return err } } return writeResult(fi, w) case eventsApi: return handleEventRequest(request, m, w, r) case psApi: // reuse container type from request. // ignore recursive. // TODO(rjnagal): consider count to limit ps output. name := getContainerName(request) glog.V(4).Infof("Api - Spec for container %q, options %+v", name, opt) ps, err := m.GetProcessList(name, opt) if err != nil { return fmt.Errorf("process listing failed: %v", err) } return writeResult(ps, w) default: return fmt.Errorf("unknown request type %q", requestType) } }
func serveContainersPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error { start := time.Now() // The container name is the path after the handler containerName := u.Path[len(ContainersPage)-1:] // Get the container. reqParams := info.ContainerInfoRequest{ NumStats: 60, } cont, err := m.GetContainerInfo(containerName, &reqParams) if err != nil { return fmt.Errorf("failed to get container %q with error: %v", containerName, err) } displayName := getContainerDisplayName(cont.ContainerReference) // Get the MachineInfo machineInfo, err := m.GetMachineInfo() if err != nil { return err } // Make a list of the parent containers and their links 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 } parentContainers = append(parentContainers, link{ Text: pathParts[i], Link: path.Join(ContainersPage, path.Join(pathParts[1:i+1]...)), }) } // 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{ DisplayName: displayName, ContainerName: cont.Name, ParentContainers: parentContainers, Subcontainers: subcontainerLinks, Spec: cont.Spec, Stats: cont.Stats, MachineInfo: machineInfo, IsRoot: cont.Name == "/", 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, FsAvailable: cont.Spec.HasFilesystem, } err = pageTemplate.Execute(w, data) if err != nil { glog.Errorf("Failed to apply template: %s", err) } glog.V(1).Infof("Request took %s", time.Since(start)) return nil }
func HandleRequest(m manager.Manager, w http.ResponseWriter, r *http.Request) error { start := time.Now() u := r.URL // Get API request type. requestType := u.Path[len(ApiResource):] i := strings.Index(requestType, "/") requestArgs := "" if i != -1 { requestArgs = requestType[i:] requestType = requestType[:i] } switch { case requestType == MachineApi: log.Printf("Api - Machine") // Get the MachineInfo machineInfo, err := m.GetMachineInfo() if err != nil { return err } out, err := json.Marshal(machineInfo) if err != nil { fmt.Fprintf(w, "Failed to marshall MachineInfo with error: %s", err) } w.Write(out) case requestType == ContainersApi: // The container name is the path after the requestType containerName := requestArgs log.Printf("Api - Container(%s)", containerName) var query info.ContainerInfoRequest // If a user does not specify number of stats/samples he wants, // it's 64 by default query.NumStats = 64 query.NumSamples = 64 decoder := json.NewDecoder(r.Body) err := decoder.Decode(&query) if err != nil && err != io.EOF { return fmt.Errorf("unable to decode the json value: ", err) } // Get the container. cont, err := m.GetContainerInfo(containerName, &query) if err != nil { fmt.Fprintf(w, "Failed to get container \"%s\" with error: %s", containerName, err) return err } // Only output the container as JSON. out, err := json.Marshal(cont) if err != nil { fmt.Fprintf(w, "Failed to marshall container %q with error: %s", containerName, err) } w.Write(out) default: return fmt.Errorf("unknown API request type %q", requestType) } log.Printf("Request took %s", time.Since(start)) return nil }