Add methods for listing and fetching container stats

This uses the previously unusued lib/stats.go code to return data
about container stats to the CRI API.

As a shortcut for intial testing, I've made ListContainerStats an API
composition of the ContainerStats and ListContainers APIs
directly (calls the same server methods with the same context), but
this should be refactored into an internal API.

No data on filesystem layer usage is returned at this time.

Fixes one-half of #1248

Signed-off-by: Yann Ramin <atrus@stackworks.net>
This commit is contained in:
Yann Ramin 2018-01-07 14:16:46 -08:00
parent 6f4d7c1ae0
commit b4a469edfe
3 changed files with 65 additions and 7 deletions

View file

@ -15,8 +15,8 @@ import (
type ContainerStats struct {
Container string
CPU float64
cpuNano uint64
systemNano uint64
CPUNano uint64
SystemNano uint64
MemUsage uint64
MemLimit uint64
MemPerc float64
@ -29,8 +29,8 @@ type ContainerStats struct {
// GetContainerStats gets the running stats for a given container
func (c *ContainerServer) GetContainerStats(ctr *oci.Container, previousStats *ContainerStats) (*ContainerStats, error) {
previousCPU := previousStats.cpuNano
previousSystem := previousStats.systemNano
previousCPU := previousStats.CPUNano
previousSystem := previousStats.SystemNano
libcontainerStats, err := c.LibcontainerStats(ctr)
if err != nil {
return nil, err

View file

@ -4,6 +4,7 @@ import (
"fmt"
"time"
"github.com/kubernetes-incubator/cri-o/lib"
"golang.org/x/net/context"
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
)
@ -16,5 +17,35 @@ func (s *Server) ContainerStats(ctx context.Context, req *pb.ContainerStatsReque
recordOperation(operation, time.Now())
recordError(operation, err)
}()
return nil, fmt.Errorf("not implemented")
container := s.GetContainer(req.ContainerId)
if container == nil {
return nil, fmt.Errorf("invalid container")
}
now := time.Now().UnixNano()
stats, err := s.GetContainerStats(container, &lib.ContainerStats{})
if err != nil {
return nil, err
}
return &pb.ContainerStatsResponse{
&pb.ContainerStats{
Attributes: &pb.ContainerAttributes{
Id: req.ContainerId,
Metadata: container.Metadata(),
Labels: container.Labels(),
Annotations: container.Annotations(),
},
Cpu: &pb.CpuUsage{
Timestamp: now,
UsageCoreNanoSeconds: &pb.UInt64Value{stats.CPUNano + stats.SystemNano},
},
Memory: &pb.MemoryUsage{
Timestamp: now,
WorkingSetBytes: &pb.UInt64Value{stats.MemUsage},
},
WritableLayer: nil,
},
}, nil
}

View file

@ -1,9 +1,9 @@
package server
import (
"fmt"
"time"
"github.com/sirupsen/logrus"
"golang.org/x/net/context"
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
)
@ -15,5 +15,32 @@ func (s *Server) ListContainerStats(ctx context.Context, req *pb.ListContainerSt
recordOperation(operation, time.Now())
recordError(operation, err)
}()
return nil, fmt.Errorf("not implemented")
// This is an inefficient method, since the container will be resolved twice,
// once by the container list code and once by the GetContainerStats call.
containers, err := s.ListContainers(ctx, &pb.ListContainersRequest{
&pb.ContainerFilter{
Id: req.Filter.Id,
PodSandboxId: req.Filter.PodSandboxId,
LabelSelector: req.Filter.LabelSelector,
},
})
if err != nil {
return nil, err
}
var allStats []*pb.ContainerStats
for _, container := range containers.Containers {
stats, err := s.ContainerStats(ctx, &pb.ContainerStatsRequest{ContainerId: container.Id})
if err != nil {
logrus.Warn("unable to get stats for container %s", container.Id)
continue
}
allStats = append(allStats, stats.Stats)
}
return &pb.ListContainerStatsResponse{
Stats: allStats,
}, nil
}