diff --git a/pkg/image/fake/store.go b/pkg/image/fake/store.go index 917b8473b..0ccc1d3b0 100644 --- a/pkg/image/fake/store.go +++ b/pkg/image/fake/store.go @@ -25,6 +25,7 @@ import ( digest "github.com/opencontainers/go-digest" "github.com/Mirantis/virtlet/pkg/image" + "github.com/Mirantis/virtlet/pkg/metadata/types" testutils "github.com/Mirantis/virtlet/pkg/utils/testing" ) @@ -133,10 +134,15 @@ func (s *FakeStore) SetRefGetter(imageRefGetter image.RefGetter) { } // FilesystemStats implements FilesystemStats method from Store interface. -func (s *FakeStore) FilesystemStats() (*image.FilesystemStats, error) { - return &image.FilesystemStats{ +func (s *FakeStore) FilesystemStats() (*types.FilesystemStats, error) { + return &types.FilesystemStats{ Mountpoint: fakeStoreMountpoint, UsedBytes: fakeUsedBytes, UsedInodes: fakeUsedInodes, }, nil } + +// BytesUsedBy implements BytesUsedBy method from Store interface. +func (s *FakeStore) BytesUsedBy(path string) (uint64, error) { + return fakeUsedBytes, nil +} diff --git a/pkg/image/image.go b/pkg/image/image.go index cc272d0bf..659e09dc5 100644 --- a/pkg/image/image.go +++ b/pkg/image/image.go @@ -30,6 +30,7 @@ import ( "github.com/golang/glog" digest "github.com/opencontainers/go-digest" + "github.com/Mirantis/virtlet/pkg/metadata/types" "github.com/Mirantis/virtlet/pkg/utils" ) @@ -57,17 +58,6 @@ type Translator func(context.Context, string) Endpoint // that are currently in use. type RefGetter func() (map[string]bool, error) -// FilesystemStats contains info about filesystem mountpoint and -// space/inodes used by images on it -type FilesystemStats struct { - // Mountpoint denotes the filesystem mount point - Mountpoint string - // UsedBytes is the number of bytes used by images - UsedBytes uint64 - // UsedInodes is the number of inodes used by images - UsedInodes uint64 -} - // Store is an interface for the image store. type Store interface { // ListImage returns the list of images in the store. @@ -101,7 +91,10 @@ type Store interface { SetRefGetter(imageRefGetter RefGetter) // FilesystemStats returns disk space and inode usage info for this store. - FilesystemStats() (*FilesystemStats, error) + FilesystemStats() (*types.FilesystemStats, error) + + // BytesUsedBy returns disk usage of the file in this store. + BytesUsedBy(path string) (uint64, error) } // VirtualSizeFunc specifies a function that returns the virtual @@ -594,7 +587,7 @@ func GetHexDigest(imageSpec string) string { // TODO: instead of returning data from filesystem we should retrieve from // metadata store sizes of images and sum them, or even retrieve precalculated // sum. That's because same filesystem could be used by other things than images. -func (s *FileStore) FilesystemStats() (*FilesystemStats, error) { +func (s *FileStore) FilesystemStats() (*types.FilesystemStats, error) { occupiedBytes, occupiedInodes, err := utils.GetFsStatsForPath(s.dir) if err != nil { return nil, err @@ -607,9 +600,18 @@ func (s *FileStore) FilesystemStats() (*FilesystemStats, error) { if err != nil { return nil, err } - return &FilesystemStats{ + return &types.FilesystemStats{ Mountpoint: mount.FSRoot, UsedBytes: occupiedBytes, UsedInodes: occupiedInodes, }, nil } + +// BytesUsedBy return disk usage of provided file as seen in store +func (s *FileStore) BytesUsedBy(path string) (uint64, error) { + fstat, err := os.Stat(path) + if err != nil { + return 0, err + } + return uint64(fstat.Size()), nil +} diff --git a/pkg/libvirttools/libvirt_domain.go b/pkg/libvirttools/libvirt_domain.go index eeb7f3884..d886a5f63 100644 --- a/pkg/libvirttools/libvirt_domain.go +++ b/pkg/libvirttools/libvirt_domain.go @@ -211,6 +211,36 @@ func (domain *libvirtDomain) XML() (*libvirtxml.Domain, error) { return &d, nil } +// GetRSS returns RSS used by VM in bytes +func (domain *libvirtDomain) GetRSS() (uint64, error) { + stats, err := domain.d.MemoryStats(uint32(libvirt.DOMAIN_MEMORY_STAT_LAST), 0) + if err != nil { + return 0, err + } + for _, stat := range stats { + if stat.Tag == int32(libvirt.DOMAIN_MEMORY_STAT_RSS) { + return stat.Val * 1024, nil + } + } + return 0, fmt.Errorf("rss not found in memory stats") +} + +// GetCPUTime returns cpu time used by VM in nanoseconds per core +func (domain *libvirtDomain) GetCPUTime() (uint64, error) { + // all vcpus as a single value + stats, err := domain.d.GetCPUStats(-1, 1, 0) + if err != nil { + return 0, err + } + if len(stats) != 1 { + return 0, fmt.Errorf("domain.GetCPUStats returned %d values while single one was expected", len(stats)) + } + if !stats[0].CpuTimeSet { + return 0, fmt.Errorf("domain.CpuTime not found in memory stats") + } + return stats[0].CpuTime, nil +} + type libvirtSecret struct { s *libvirt.Secret } diff --git a/pkg/libvirttools/root_volumesource_test.go b/pkg/libvirttools/root_volumesource_test.go index 88f85d956..4f03aec31 100644 --- a/pkg/libvirttools/root_volumesource_test.go +++ b/pkg/libvirttools/root_volumesource_test.go @@ -30,8 +30,10 @@ import ( ) const ( - testUUID = "77f29a0e-46af-4188-a6af-9ff8b8a65224" - fakeImageVirtualSize = 424242 + testUUID = "77f29a0e-46af-4188-a6af-9ff8b8a65224" + fakeImageVirtualSize = 424242 + fakeImageStoreUsedBytes = 424242 + fakeImageStoreUsedInodes = 424242 ) type FakeImageManager struct { @@ -51,6 +53,19 @@ func (im *FakeImageManager) GetImagePathAndVirtualSize(imageName string) (string return "/fake/volume/path", fakeImageVirtualSize, nil } +func (im *FakeImageManager) FilesystemStats() (*types.FilesystemStats, error) { + return &types.FilesystemStats{ + Mountpoint: "/some/dir", + UsedBytes: fakeImageStoreUsedBytes, + UsedInodes: fakeImageStoreUsedInodes, + }, nil +} + +func (im *FakeImageManager) BytesUsedBy(path string) (uint64, error) { + im.rec.Rec("BytesUsedBy", path) + return fakeImageVirtualSize, nil +} + func TestRootVolumeNaming(t *testing.T) { v := rootVolume{ volumeBase{ diff --git a/pkg/libvirttools/virtualization.go b/pkg/libvirttools/virtualization.go index d7865e479..4c3f59d07 100644 --- a/pkg/libvirttools/virtualization.go +++ b/pkg/libvirttools/virtualization.go @@ -19,6 +19,7 @@ package libvirttools import ( "fmt" "path/filepath" + "strings" "time" "github.com/golang/glog" @@ -809,9 +810,98 @@ func (v *VirtualizationTool) ContainerInfo(containerID string) (*types.Container return containerInfo, nil } +// VMStats returns current cpu/memory/disk usage for VM +func (v *VirtualizationTool) VMStats(containerID string, name string) (*types.VMStats, error) { + domain, err := v.domainConn.LookupDomainByUUIDString(containerID) + if err != nil { + return nil, err + } + vs := types.VMStats{ + Timestamp: v.clock.Now().UnixNano(), + ContainerID: containerID, + Name: name, + } + + rss, err := domain.GetRSS() + if err != nil { + return nil, err + } + vs.MemoryUsage = rss + + cpuTime, err := domain.GetCPUTime() + if err != nil { + return nil, err + } + vs.CpuUsage = cpuTime + + domainxml, err := domain.XML() + if err != nil { + return nil, err + } + + rootDiskLocation := "" + for _, disk := range domainxml.Devices.Disks { + if disk.Source == nil || disk.Source.File == nil { + continue + } + fname := disk.Source.File.File + // TODO: split file name and use HasPrefix on last part + // instead of Contains + if strings.Contains(fname, "virtlet_root_") { + rootDiskLocation = fname + } + } + if rootDiskLocation == "" { + return nil, fmt.Errorf("cannot locate root disk in domain definition") + } + + rootDiskSize, err := v.ImageManager().BytesUsedBy(rootDiskLocation) + if err != nil { + return nil, err + } + vs.FsBytes = rootDiskSize + + glog.V(4).Infof("VMStats - cpu: %d, mem: %d, disk: %d, timestamp: %d", vs.CpuUsage, vs.MemoryUsage, vs.FsBytes, vs.Timestamp) + + return &vs, nil +} + +// ListVMStats returns statistics (same as VMStats) for all containers matching +// provided filter (id AND podstandboxid AND labels) +func (v *VirtualizationTool) ListVMStats(filter *types.VMStatsFilter) ([]types.VMStats, error) { + var containersFilter *types.ContainerFilter + if filter != nil { + containersFilter = &types.ContainerFilter{} + if filter.Id != "" { + containersFilter.Id = filter.Id + } + if filter.PodSandboxID != "" { + containersFilter.PodSandboxID = filter.PodSandboxID + } + if filter.LabelSelector != nil { + containersFilter.LabelSelector = filter.LabelSelector + } + } + + infos, err := v.ListContainers(containersFilter) + if err != nil { + return nil, err + } + + var statsList []types.VMStats + for _, info := range infos { + stats, err := v.VMStats(info.Id, info.Name) + if err != nil { + return nil, err + } + statsList = append(statsList, *stats) + } + return statsList, nil +} + // volumeOwner implementation follows -// StoragePool returns StoragePool for volumes +// StoragePool implements volumeOwner StoragePool method func (v *VirtualizationTool) StoragePool() (virt.StoragePool, error) { return ensureStoragePool(v.storageConn, v.config.VolumePoolName) } diff --git a/pkg/libvirttools/volumes.go b/pkg/libvirttools/volumes.go index d4f496073..41ef7e3b1 100644 --- a/pkg/libvirttools/volumes.go +++ b/pkg/libvirttools/volumes.go @@ -27,6 +27,8 @@ import ( // ImageManager describes a images info provider. type ImageManager interface { GetImagePathAndVirtualSize(ref string) (string, uint64, error) + FilesystemStats() (*types.FilesystemStats, error) + BytesUsedBy(path string) (uint64, error) } type volumeOwner interface { diff --git a/pkg/manager/TestCRIPods.out.yaml b/pkg/manager/TestCRIPods.out.yaml index 6abe8c710..31ac0603c 100755 --- a/pkg/manager/TestCRIPods.out.yaml +++ b/pkg/manager/TestCRIPods.out.yaml @@ -301,6 +301,56 @@ name: container-for-testName_0 started_at: 1524648266720331175 state: 1 +- name: 'enter: ContainerStats' + value: + container_id: 231700d5-c9a6-5a49-738d-99a954c51550 +- name: 'leave: ContainerStats' + value: + stats: + attributes: + id: 231700d5-c9a6-5a49-738d-99a954c51550 + metadata: + name: 231700d5-c9a6-5a49-738d-99a954c51550 + cpu: + timestamp: 1524648266720331175 + usage_core_nano_seconds: {} + memory: + timestamp: 1524648266720331175 + working_set_bytes: {} + writable_layer: + fs_id: + mountpoint: /var/lib/virtlet + inodes_used: + value: 1 + timestamp: 1524648266720331175 + used_bytes: + value: 1073741824 +- name: 'enter: ListContainerStats' + value: {} +- name: 'domain conn: ListDomains' + value: + - virtlet-231700d5-c9a6-container-for-testName_0 +- name: 'leave: ListContainerStats' + value: + stats: + - attributes: + id: 231700d5-c9a6-5a49-738d-99a954c51550 + metadata: + name: 231700d5-c9a6-5a49-738d-99a954c51550 + cpu: + timestamp: 1524648266720331175 + usage_core_nano_seconds: {} + memory: + timestamp: 1524648266720331175 + working_set_bytes: {} + writable_layer: + fs_id: + mountpoint: /var/lib/virtlet + inodes_used: + value: 1 + timestamp: 1524648266720331175 + used_bytes: + value: 1073741824 - name: 'enter: PullImage' value: image: diff --git a/pkg/manager/TestContainerListStats.out.yaml b/pkg/manager/TestContainerListStats.out.yaml new file mode 100755 index 000000000..ebfba8005 --- /dev/null +++ b/pkg/manager/TestContainerListStats.out.yaml @@ -0,0 +1,117 @@ +- name: 'enter: ListContainerStats' + value: {} +- name: 'leave: ListContainerStats' + value: + stats: + - attributes: + id: 231700d5-c9a6-5a49-738d-99a954c51550 + metadata: + name: 231700d5-c9a6-5a49-738d-99a954c51550 + cpu: + timestamp: 1524648266720331175 + usage_core_nano_seconds: {} + memory: + timestamp: 1524648266720331175 + working_set_bytes: {} + writable_layer: + fs_id: + mountpoint: /var/lib/virtlet + inodes_used: + value: 1 + timestamp: 1524648266720331175 + used_bytes: + value: 1073741824 + - attributes: + id: 6b94d9a7-e22a-5d08-65ee-16b9b1e07ab0 + metadata: + name: 6b94d9a7-e22a-5d08-65ee-16b9b1e07ab0 + cpu: + timestamp: 1524648266720331175 + usage_core_nano_seconds: {} + memory: + timestamp: 1524648266720331175 + working_set_bytes: {} + writable_layer: + fs_id: + mountpoint: /var/lib/virtlet + inodes_used: + value: 1 + timestamp: 1524648266720331175 + used_bytes: + value: 1073741824 +- name: 'enter: ListContainerStats' + value: + filter: + id: 231700d5-c9a6-5a49-738d-99a954c51550 +- name: 'leave: ListContainerStats' + value: + stats: + - attributes: + id: 231700d5-c9a6-5a49-738d-99a954c51550 + metadata: + name: 231700d5-c9a6-5a49-738d-99a954c51550 + cpu: + timestamp: 1524648266720331175 + usage_core_nano_seconds: {} + memory: + timestamp: 1524648266720331175 + working_set_bytes: {} + writable_layer: + fs_id: + mountpoint: /var/lib/virtlet + inodes_used: + value: 1 + timestamp: 1524648266720331175 + used_bytes: + value: 1073741824 +- name: 'enter: ListContainerStats' + value: + filter: + label_selector: + io.kubernetes.pod.name: testName_1 +- name: 'leave: ListContainerStats' + value: + stats: + - attributes: + id: 6b94d9a7-e22a-5d08-65ee-16b9b1e07ab0 + metadata: + name: 6b94d9a7-e22a-5d08-65ee-16b9b1e07ab0 + cpu: + timestamp: 1524648266720331175 + usage_core_nano_seconds: {} + memory: + timestamp: 1524648266720331175 + working_set_bytes: {} + writable_layer: + fs_id: + mountpoint: /var/lib/virtlet + inodes_used: + value: 1 + timestamp: 1524648266720331175 + used_bytes: + value: 1073741824 +- name: 'enter: ListContainerStats' + value: + filter: + pod_sandbox_id: 69eec606-0493-5825-73a4-c5e0c0236155 +- name: 'leave: ListContainerStats' + value: + stats: + - attributes: + id: 231700d5-c9a6-5a49-738d-99a954c51550 + metadata: + name: 231700d5-c9a6-5a49-738d-99a954c51550 + cpu: + timestamp: 1524648266720331175 + usage_core_nano_seconds: {} + memory: + timestamp: 1524648266720331175 + working_set_bytes: {} + writable_layer: + fs_id: + mountpoint: /var/lib/virtlet + inodes_used: + value: 1 + timestamp: 1524648266720331175 + used_bytes: + value: 1073741824 diff --git a/pkg/manager/cri.go b/pkg/manager/cri.go index c3b4ee583..6a7ce7ac0 100644 --- a/pkg/manager/cri.go +++ b/pkg/manager/cri.go @@ -192,6 +192,18 @@ func CRIContainerFilterToContainerFilter(in *kubeapi.ContainerFilter) *types.Con } } +// CRIContainerStatsFilterToVMStatsFilter converts CRI ContainerStatsFilter to VMStatsFilter. +func CRIContainerStatsFilterToVMStatsFilter(in *kubeapi.ContainerStatsFilter) *types.VMStatsFilter { + if in == nil { + return nil + } + return &types.VMStatsFilter{ + Id: in.Id, + PodSandboxID: in.PodSandboxId, + LabelSelector: in.LabelSelector, + } +} + func containerMetadata(in *types.ContainerInfo) *kubeapi.ContainerMetadata { return &kubeapi.ContainerMetadata{ Name: in.Name, diff --git a/pkg/manager/runtime.go b/pkg/manager/runtime.go index ade03a88d..34f8028c0 100644 --- a/pkg/manager/runtime.go +++ b/pkg/manager/runtime.go @@ -456,14 +456,74 @@ func (v *VirtletRuntimeService) Status(context.Context, *kubeapi.StatusRequest) }, nil } -// ContainerStats is a placeholder for an unimplemented CRI method. +// ContainerStats returns cpu/memory/disk usage for particular container id func (v *VirtletRuntimeService) ContainerStats(ctx context.Context, in *kubeapi.ContainerStatsRequest) (*kubeapi.ContainerStatsResponse, error) { - return nil, errors.New("ContainerStats() not implemented") + info, err := v.virtTool.ContainerInfo(in.ContainerId) + if err != nil { + return nil, err + } + vs, err := v.virtTool.VMStats(info.Id, info.Name) + if err != nil { + return nil, err + } + fsstats, err := v.virtTool.ImageManager().FilesystemStats() + if err != nil { + return nil, err + } + return &kubeapi.ContainerStatsResponse{ + Stats: VMStatsToCRIContainerStats(*vs, fsstats.Mountpoint), + }, nil } -// ListContainerStats is a placeholder for an unimplemented CRI method. +// ListContainerStats returns stats (same as ContainerStats) for containers +// selected by filter func (v *VirtletRuntimeService) ListContainerStats(ctx context.Context, in *kubeapi.ListContainerStatsRequest) (*kubeapi.ListContainerStatsResponse, error) { - return nil, errors.New("ListContainerStats() not implemented") + filter := CRIContainerStatsFilterToVMStatsFilter(in.GetFilter()) + vmstatsList, err := v.virtTool.ListVMStats(filter) + if err != nil { + return nil, err + } + fsstats, err := v.virtTool.ImageManager().FilesystemStats() + if err != nil { + return nil, err + } + var stats []*kubeapi.ContainerStats + for _, vs := range vmstatsList { + stats = append(stats, VMStatsToCRIContainerStats(vs, fsstats.Mountpoint)) + } + + return &kubeapi.ListContainerStatsResponse{ + Stats: stats, + }, nil +} + +// VMStatsToCRIContainerStats converts internal representation of vm/container stats +// to corresponding kubeapi type object +func VMStatsToCRIContainerStats(vs types.VMStats, mountpoint string) *kubeapi.ContainerStats { + return &kubeapi.ContainerStats{ + Attributes: &kubeapi.ContainerAttributes{ + Id: vs.ContainerID, + Metadata: &kubeapi.ContainerMetadata{ + Name: vs.ContainerID, + }, + }, + Cpu: &kubeapi.CpuUsage{ + Timestamp: vs.Timestamp, + UsageCoreNanoSeconds: &kubeapi.UInt64Value{Value: vs.CpuUsage}, + }, + Memory: &kubeapi.MemoryUsage{ + Timestamp: vs.Timestamp, + WorkingSetBytes: &kubeapi.UInt64Value{Value: vs.MemoryUsage}, + }, + WritableLayer: &kubeapi.FilesystemUsage{ + Timestamp: vs.Timestamp, + FsId: &kubeapi.FilesystemIdentifier{ + Mountpoint: mountpoint, + }, + UsedBytes: &kubeapi.UInt64Value{Value: vs.FsBytes}, + InodesUsed: &kubeapi.UInt64Value{Value: 1}, + }, + } } // ReopenContainerLog is a placeholder for an unimplemented CRI method. diff --git a/pkg/manager/runtime_test.go b/pkg/manager/runtime_test.go index f02db3789..e11918365 100644 --- a/pkg/manager/runtime_test.go +++ b/pkg/manager/runtime_test.go @@ -370,6 +370,10 @@ func (tst *virtletCRITester) listContainers(filter *kubeapi.ContainerFilter) { tst.invoke("ListContainers", &kubeapi.ListContainersRequest{Filter: filter}, true) } +func (tst *virtletCRITester) listContainerStats(filter *kubeapi.ContainerStatsFilter) { + tst.invoke("ListContainerStats", &kubeapi.ListContainerStatsRequest{Filter: filter}, true) +} + func (tst *virtletCRITester) createContainer(sandbox *kubeapi.PodSandboxConfig, container *criapi.ContainerTestConfig, imageSpec *kubeapi.ImageSpec, mounts []*kubeapi.Mount) string { req := createContainerRequest(sandbox, container, imageSpec, mounts) resp, err := tst.invoke("CreateContainer", req, true) @@ -397,6 +401,10 @@ func (tst *virtletCRITester) stopContainer(containerID string) { tst.invoke("StopContainer", &kubeapi.StopContainerRequest{ContainerId: containerID}, true) } +func (tst *virtletCRITester) containerStats(containerID string) { + tst.invoke("ContainerStats", &kubeapi.ContainerStatsRequest{ContainerId: containerID}, true) +} + func (tst *virtletCRITester) removeContainer(containerID string) { tst.invoke("RemoveContainer", &kubeapi.RemoveContainerRequest{ContainerId: containerID}, true) } @@ -457,6 +465,8 @@ func TestCRIPods(t *testing.T) { tst.containerStatus(containerId1) tst.startContainer(containerId1) tst.containerStatus(containerId1) + tst.containerStats(containerId1) + tst.listContainerStats(nil) tst.pullImage(ubuntuImg()) tst.runPodSandbox(sandboxes[1]) @@ -626,6 +636,37 @@ func TestCRIContainerFilters(t *testing.T) { tst.verify() } +func TestContainerListStats(t *testing.T) { + tst := makeVirtletCRITester(t) + tst.rec.AddFilter("ListContainers") + tst.rec.AddFilter("ListContainerStats") + defer tst.teardown() + + sandboxes := criapi.GetSandboxes(2) + containers := criapi.GetContainersConfig(sandboxes) + tst.pullImage(cirrosImg()) + tst.runPodSandbox(sandboxes[0]) + containerId1 := tst.createContainer(sandboxes[0], containers[0], cirrosImg(), nil) + tst.startContainer(containerId1) + tst.pullImage(ubuntuImg()) + tst.runPodSandbox(sandboxes[1]) + containerId2 := tst.createContainer(sandboxes[1], containers[1], ubuntuImg(), nil) + tst.startContainer(containerId2) + + tst.listContainerStats(nil) + tst.listContainerStats(&kubeapi.ContainerStatsFilter{Id: containerId1}) + tst.listContainerStats(&kubeapi.ContainerStatsFilter{ + LabelSelector: map[string]string{ + "io.kubernetes.pod.name": "testName_1", + }, + }) + tst.listContainerStats(&kubeapi.ContainerStatsFilter{ + PodSandboxId: sandboxes[0].Metadata.Uid, + }) + + tst.verify() +} + func TestCRIAttachPortForward(t *testing.T) { tst := makeVirtletCRITester(t) tst.rec.AddFilter("Attach") diff --git a/pkg/metadata/types/types.go b/pkg/metadata/types/types.go index a54e6d682..4eefecd46 100644 --- a/pkg/metadata/types/types.go +++ b/pkg/metadata/types/types.go @@ -90,6 +90,25 @@ type ContainerInfo struct { Config VMConfig } +// VMStats contains cpu/memory/disk usage for VM. +type VMStats struct { + // ContainerID holds identifier of container for which these statistics + // were collected + ContainerID string + // Name holds name of the container + Name string + // Timestatmp holds an unix timestamp (including nanoseconds) + // for stats collection + Timestamp int64 + // CpuUsage in nano seconds per cpu + CpuUsage uint64 + // MemoryUsage is expected to contain the amount of working set memory + // in bytes what in our case will be returned using RSS value + MemoryUsage uint64 + // FsBytes represents current size of rootfs in bytes + FsBytes uint64 +} + // NamespaceOption provides options for Linux namespaces. type NamespaceOption struct { // If set, use the host's network namespace. @@ -277,3 +296,26 @@ type ContainerFilter struct { // are ANDed. MatchExpressions is not supported yet. LabelSelector map[string]string } + +// VMStatsFilter is used to filter set of container stats +// All those fields are combined with 'AND' +type VMStatsFilter struct { + // ID holds of the container. + Id string + // PodSandboxID holds id of podsandbox. + PodSandboxID string + // LabelSelector to select matches. Requirementes should be ANDed. + // Match Expressions is not supported. + LabelSelector map[string]string +} + +// FilesystemStats contains info about filesystem mountpoint and +// space/inodes used by images on it +type FilesystemStats struct { + // Mountpoint denotes the filesystem mount point + Mountpoint string + // UsedBytes is the number of bytes used by images + UsedBytes uint64 + // UsedInodes is the number of inodes used by images + UsedInodes uint64 +} diff --git a/pkg/virt/domain_interface.go b/pkg/virt/domain_interface.go index c02b8a8ac..5381f8c55 100644 --- a/pkg/virt/domain_interface.go +++ b/pkg/virt/domain_interface.go @@ -105,4 +105,8 @@ type Domain interface { Name() (string, error) // XML retrieves xml definition of the domain XML() (*libvirtxml.Domain, error) + // GetRSS returns RSS used by VM in bytes + GetRSS() (uint64, error) + // GetCPUTime returns cpu time used by VM in nanoseconds per core + GetCPUTime() (uint64, error) } diff --git a/pkg/virt/fake/fake_domain.go b/pkg/virt/fake/fake_domain.go index eb566308d..39e3329f0 100644 --- a/pkg/virt/fake/fake_domain.go +++ b/pkg/virt/fake/fake_domain.go @@ -312,6 +312,16 @@ func (d *FakeDomain) XML() (*libvirtxml.Domain, error) { return d.def, nil } +// GetCPUTime implements GetCPUTime of Domain interface. +func (d *FakeDomain) GetCPUTime() (uint64, error) { + return 0, nil +} + +// GetRSS implements GetRSS of Domain interface. +func (d *FakeDomain) GetRSS() (uint64, error) { + return 0, nil +} + // FakeSecret is a fake implementation of Secret interace. type FakeSecret struct { rec testutils.Recorder