diff --git a/go.mod b/go.mod index 4abc5c35e12..3cee3e8b37c 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,10 @@ require ( github.com/BurntSushi/toml v0.3.1 github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3 github.com/blang/semver v3.5.1+incompatible + github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68 github.com/containerd/containerd v1.5.0-beta.4 github.com/containerd/ttrpc v1.0.2 + github.com/containerd/typeurl v1.0.1 github.com/containernetworking/cni v0.8.1 github.com/containernetworking/plugins v0.9.1 github.com/containers/buildah v1.20.0 diff --git a/internal/oci/oci_linux.go b/internal/oci/oci_linux.go index 3a63df3545e..a200195ddc4 100644 --- a/internal/oci/oci_linux.go +++ b/internal/oci/oci_linux.go @@ -111,56 +111,6 @@ func (r *runtimeOCI) containerStats(ctr *Container, cgroup string) (*ContainerSt return stats, nil } -func metricsToCtrStats(c *Container, m *cgroups.Metrics) *ContainerStats { - var ( - cpu float64 - cpuNano uint64 - memUsage uint64 - memLimit uint64 - memPerc float64 - netInput uint64 - netOutput uint64 - blockInput uint64 - blockOutput uint64 - pids uint64 - ) - - if m != nil { - pids = m.Pids.Current - - cpuNano = m.CPU.Usage.Total - cpu = genericCalculateCPUPercent(cpuNano, m.CPU.Usage.PerCPU) - - memUsage = m.Memory.Usage.Usage - memLimit = getMemLimit(m.Memory.Usage.Limit) - memPerc = float64(memUsage) / float64(memLimit) - - for _, entry := range m.Blkio.IoServiceBytesRecursive { - switch strings.ToLower(entry.Op) { - case "read": - blockInput += entry.Value - case "write": - blockOutput += entry.Value - } - } - } - - return &ContainerStats{ - Container: c.ID(), - CPU: cpu, - CPUNano: cpuNano, - SystemNano: time.Now().UnixNano(), - MemUsage: memUsage, - MemLimit: memLimit, - MemPerc: memPerc, - NetInput: netInput, - NetOutput: netOutput, - BlockInput: blockInput, - BlockOutput: blockOutput, - PIDs: pids, - } -} - // getTotalInactiveFile returns the value if inactive_file as integer // from cgroup's memory.stat. Returns an error if the file does not exists, // not parsable, or the value is not found. diff --git a/internal/oci/runtime_vm.go b/internal/oci/runtime_vm.go index 36fdccb2287..b0454692041 100644 --- a/internal/oci/runtime_vm.go +++ b/internal/oci/runtime_vm.go @@ -11,12 +11,13 @@ import ( "syscall" "time" + cgroups "github.com/containerd/cgroups/stats/v1" tasktypes "github.com/containerd/containerd/api/types/task" "github.com/containerd/containerd/namespaces" client "github.com/containerd/containerd/runtime/v2/shim" "github.com/containerd/containerd/runtime/v2/task" "github.com/containerd/ttrpc" - "github.com/containers/podman/v3/pkg/cgroups" + "github.com/containerd/typeurl" "github.com/cri-o/cri-o/internal/log" "github.com/cri-o/cri-o/server/metrics" "github.com/cri-o/cri-o/utils" @@ -24,7 +25,6 @@ import ( "github.com/cri-o/cri-o/utils/fifo" cio "github.com/cri-o/cri-o/utils/io" cioutil "github.com/cri-o/cri-o/utils/ioutil" - "github.com/cri-o/cri-o/utils/typeurl" rspec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -746,6 +746,66 @@ func (r *runtimeVM) ContainerStats(ctx context.Context, c *Container, _ string) return metricsToCtrStats(c, m), nil } +func metricsToCtrStats(c *Container, m *cgroups.Metrics) *ContainerStats { + var ( + blockInput uint64 + blockOutput uint64 + cpu float64 + cpuNano uint64 + memLimit uint64 + memPerc float64 + memUsage uint64 + netInput uint64 + netOutput uint64 + pids uint64 + workingSetBytes uint64 + ) + + if m != nil { + pids = m.Pids.Current + + cpuNano = m.CPU.Usage.Total + cpu = genericCalculateCPUPercent(cpuNano, m.CPU.Usage.PerCPU) + + memUsage = m.Memory.Usage.Usage + memLimit = getMemLimit(m.Memory.Usage.Limit) + memPerc = float64(memUsage) / float64(memLimit) + if memUsage > m.Memory.TotalInactiveFile { + workingSetBytes = memUsage - m.Memory.TotalInactiveFile + } else { + logrus.Debugf( + "unable to account working set stats: total_inactive_file (%d) > memory usage (%d)", + m.Memory.TotalInactiveFile, memUsage, + ) + } + + for _, entry := range m.Blkio.IoServiceBytesRecursive { + switch strings.ToLower(entry.Op) { + case "read": + blockInput += entry.Value + case "write": + blockOutput += entry.Value + } + } + } + + return &ContainerStats{ + BlockInput: blockInput, + BlockOutput: blockOutput, + Container: c.ID(), + CPU: cpu, + CPUNano: cpuNano, + MemLimit: memLimit, + MemUsage: memUsage, + MemPerc: memPerc, + NetInput: netInput, + NetOutput: netOutput, + PIDs: pids, + SystemNano: time.Now().UnixNano(), + WorkingSetBytes: workingSetBytes, + } +} + // SignalContainer sends a signal to a container process. func (r *runtimeVM) SignalContainer(ctx context.Context, c *Container, sig syscall.Signal) error { log.Debugf(ctx, "runtimeVM.SignalContainer() start") diff --git a/utils/typeurl/types.go b/utils/typeurl/types.go deleted file mode 100644 index e4bdeeba470..00000000000 --- a/utils/typeurl/types.go +++ /dev/null @@ -1,158 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - - You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package typeurl - -import ( - "path" - "reflect" - "sync" - - "github.com/gogo/protobuf/proto" - "github.com/gogo/protobuf/types" - json "github.com/json-iterator/go" - "github.com/pkg/errors" -) - -var ( - mu sync.Mutex - registry = make(map[reflect.Type]string) -) - -var errNotFound = errors.New("not found") - -// Register a type with the base url of the type -func Register(v interface{}, args ...string) { - var ( - t = tryDereference(v) - p = path.Join(args...) - ) - mu.Lock() - defer mu.Unlock() - if et, ok := registry[t]; ok { - if et != p { - panic(errors.Errorf("type registred with alternate path %q != %q", et, p)) - } - return - } - registry[t] = p -} - -// TypeURL returns the type url for a registred type -func TypeURL(v interface{}) (string, error) { - mu.Lock() - u, ok := registry[tryDereference(v)] - mu.Unlock() - if !ok { - // fallback to the proto registry if it is a proto message - pb, ok := v.(proto.Message) - if !ok { - return "", errors.Wrapf(errNotFound, "type %s", reflect.TypeOf(v)) - } - return proto.MessageName(pb), nil - } - return u, nil -} - -// Is returns true if the type of the Any is the same as v -func Is(any *types.Any, v interface{}) bool { - // call to check that v is a pointer - tryDereference(v) - url, err := TypeURL(v) - if err != nil { - return false - } - return any.TypeUrl == url -} - -// MarshalAny marshals the value v into an any with the correct TypeUrl -func MarshalAny(v interface{}) (*types.Any, error) { - var marshal func(v interface{}) ([]byte, error) - switch t := v.(type) { - case *types.Any: - // avoid reserializing the type if we have an any. - return t, nil - case proto.Message: - marshal = func(v interface{}) ([]byte, error) { - return proto.Marshal(t) - } - default: - marshal = json.Marshal - } - - url, err := TypeURL(v) - if err != nil { - return nil, err - } - - data, err := marshal(v) - if err != nil { - return nil, err - } - return &types.Any{ - TypeUrl: url, - Value: data, - }, nil -} - -// UnmarshalAny unmarshals the any type into a concrete type -func UnmarshalAny(any *types.Any) (interface{}, error) { - t, err := getTypeByURL(any.TypeUrl) - if err != nil { - return nil, err - } - v := reflect.New(t.t).Interface() - if t.isProto { - err = proto.Unmarshal(any.Value, v.(proto.Message)) - } else { - err = json.Unmarshal(any.Value, v) - } - return v, err -} - -type urlType struct { - t reflect.Type - isProto bool -} - -func getTypeByURL(url string) (urlType, error) { - for t, u := range registry { - if u == url { - return urlType{ - t: t, - }, nil - } - } - // fallback to proto registry - t := proto.MessageType(url) - if t != nil { - return urlType{ - // get the underlying Elem because proto returns a pointer to the type - t: t.Elem(), - isProto: true, - }, nil - } - return urlType{}, errors.Wrapf(errNotFound, "type with url %s", url) -} - -func tryDereference(v interface{}) reflect.Type { - t := reflect.TypeOf(v) - if t.Kind() == reflect.Ptr { - // require check of pointer but dereference to register - return t.Elem() - } - panic("v is not a pointer to a type") -} diff --git a/vendor/modules.txt b/vendor/modules.txt index eaaf1f82933..35c006a4268 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -59,6 +59,7 @@ github.com/cilium/ebpf/internal github.com/cilium/ebpf/internal/btf github.com/cilium/ebpf/internal/unix # github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68 +## explicit github.com/containerd/cgroups/stats/v1 # github.com/containerd/console v1.0.1 github.com/containerd/console @@ -93,6 +94,7 @@ github.com/containerd/go-runc ## explicit github.com/containerd/ttrpc # github.com/containerd/typeurl v1.0.1 +## explicit github.com/containerd/typeurl # github.com/containernetworking/cni v0.8.1 ## explicit