예제 #1
0
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()
		}
	}
}
예제 #2
0
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)
	}
}
예제 #3
0
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
}
예제 #4
0
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)
	}
}
예제 #5
0
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)
	}
}
예제 #6
0
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)
	}
}
예제 #7
0
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
}
예제 #8
0
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)
	}()
}
예제 #9
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)
	}
}
예제 #10
0
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
}
예제 #11
0
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)
	}
}
예제 #12
0
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
}
예제 #13
0
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)

}
예제 #14
0
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
}
예제 #15
0
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)
	}
}
예제 #16
0
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
}
예제 #17
0
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
}
예제 #18
0
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
}
예제 #19
0
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)
	}
}
예제 #20
0
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
}
예제 #21
0
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
}