func getContainerInfoRequest(body io.ReadCloser) (*info.ContainerInfoRequest, error) { var query info.ContainerInfoRequest // Default stats and samples is 64. query.NumStats = 64 decoder := json.NewDecoder(body) err := decoder.Decode(&query) if err != nil && err != io.EOF { return nil, fmt.Errorf("unable to decode the json value: %s", err) } return &query, nil }
// Get a container by name. func (m *manager) GetContainerInfo(containerName string, query *info.ContainerInfoRequest) (*info.ContainerInfo, error) { log.Printf("Get(%s); %+v", containerName, query) var cont *containerData var ok bool func() { m.containersLock.RLock() defer m.containersLock.RUnlock() // Ensure we have the container. cont, ok = m.containers[containerName] }() if !ok { return nil, fmt.Errorf("unknown container \"%s\"", containerName) } // Get the info from the container. cinfo, err := cont.GetInfo() if err != nil { return nil, err } var percentiles *info.ContainerStatsPercentiles var samples []*info.ContainerStatsSample var stats []*info.ContainerStats query = query.FillDefaults() percentiles, err = m.storageDriver.Percentiles( cinfo.Name, query.CpuUsagePercentiles, query.MemoryUsagePercentages, ) if err != nil { return nil, err } samples, err = m.storageDriver.Samples(cinfo.Name, query.NumSamples) if err != nil { return nil, err } stats, err = m.storageDriver.RecentStats(cinfo.Name, query.NumStats) if err != nil { return nil, err } // Make a copy of the info for the user. ret := &info.ContainerInfo{ ContainerReference: info.ContainerReference{ Name: cinfo.Name, Aliases: cinfo.Aliases, }, Subcontainers: cinfo.Subcontainers, Spec: cinfo.Spec, StatsPercentiles: percentiles, Samples: samples, Stats: stats, } // Set default value to an actual value if ret.Spec.Memory != nil { // Memory.Limit is 0 means there's no limit if ret.Spec.Memory.Limit == 0 { ret.Spec.Memory.Limit = uint64(m.machineInfo.MemoryCapacity) } } return ret, nil }
func TestGetContainerInfoWithDefaultValue(t *testing.T) { containers := []string{ "/c1", "/c2", } var query *info.ContainerInfoRequest query = query.FillDefaults() infosMap := make(map[string]*info.ContainerInfo, len(containers)) handlerMap := make(map[string]*ctest.MockContainerHandler, len(containers)) for _, container := range containers { infosMap[container] = itest.GenerateRandomContainerInfo(container, 4, query, 1*time.Second) } driver := &stest.MockStorageDriver{} m := createManagerAndAddContainers( driver, containers, func(h *ctest.MockContainerHandler) { cinfo := infosMap[h.Name] stats := cinfo.Stats samples := cinfo.Samples percentiles := cinfo.StatsPercentiles spec := cinfo.Spec driver.On( "Percentiles", h.Name, query.CpuUsagePercentiles, query.MemoryUsagePercentages, ).Return( percentiles, nil, ) driver.On( "Samples", h.Name, query.NumSamples, ).Return( samples, nil, ) driver.On( "RecentStats", h.Name, query.NumStats, ).Return( stats, nil, ) h.On("ListContainers", container.LIST_SELF).Return( []info.ContainerReference(nil), nil, ) h.On("GetSpec").Return( spec, nil, ) handlerMap[h.Name] = h }, t, ) returnedInfos := make(map[string]*info.ContainerInfo, len(containers)) for _, container := range containers { // nil should give us default values cinfo, err := m.GetContainerInfo(container, nil) if err != nil { t.Fatalf("Unable to get info for container %v: %v", container, err) } returnedInfos[container] = cinfo } for container, handler := range handlerMap { handler.AssertExpectations(t) returned := returnedInfos[container] expected := infosMap[container] if !reflect.DeepEqual(returned, expected) { t.Errorf("returned unexpected info for container %v; returned %+v; expected %+v", container, returned, expected) } } }
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 }