diff --git a/docs/source/markdown/podman-info.1.md b/docs/source/markdown/podman-info.1.md index d68d188194..e398202571 100644 --- a/docs/source/markdown/podman-info.1.md +++ b/docs/source/markdown/podman-info.1.md @@ -75,6 +75,7 @@ host: kernel: 5.13.13-200.fc34.x86_64 linkmode: dynamic logDriver: journald + memAvailable: 14567456768 memFree: 1833385984 memTotal: 16401895424 networkBackend: netavark @@ -218,6 +219,7 @@ $ podman info --format json }, "kernel": "5.13.13-200.fc34.x86_64", "logDriver": "journald", + "memAvailable": 14567456768, "memFree": 1785753600, "memTotal": 16401895424, "networkBackend": "netavark", diff --git a/libpod/define/info.go b/libpod/define/info.go index 84995629d4..b20e9dcfab 100644 --- a/libpod/define/info.go +++ b/libpod/define/info.go @@ -47,6 +47,7 @@ type HostInfo struct { Kernel string `json:"kernel"` LogDriver string `json:"logDriver"` MemFree int64 `json:"memFree"` + MemAvailable int64 `json:"memAvailable"` MemTotal int64 `json:"memTotal"` NetworkBackend string `json:"networkBackend"` NetworkBackendInfo types.NetworkInfo `json:"networkBackendInfo"` diff --git a/libpod/info.go b/libpod/info.go index 58515f6afa..a9dec0609f 100644 --- a/libpod/info.go +++ b/libpod/info.go @@ -122,6 +122,7 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) { Hostname: host, Kernel: kv, MemFree: mi.MemFree, + MemAvailable: mi.MemAvailable, MemTotal: mi.MemTotal, NetworkBackend: r.config.Network.NetworkBackend, NetworkBackendInfo: r.network.NetworkInfo(), diff --git a/test/apiv2/45-system.at b/test/apiv2/45-system.at index 560c039b3c..5af317dd31 100644 --- a/test/apiv2/45-system.at +++ b/test/apiv2/45-system.at @@ -12,7 +12,10 @@ t GET /v1.52/system/df 200 '{"ImageUsage":{},"ContainerUsage":{},"VolumeUsage":{ t GET libpod/system/df 200 '{"ImagesSize":0,"Images":[],"Containers":[],"Volumes":[]}' # Create volume. We expect df to report this volume next invocation of system/df -t GET libpod/info 200 +t GET libpod/info 200 \ + .host.memTotal~[0-9]\\+ \ + .host.memFree~[0-9]\\+ \ + .host.memAvailable~[0-9]\\+ volumepath=$(jq -r ".store.volumePath" <<<"$output") t POST libpod/volumes/create name=foo1 201 \ .Name=foo1 \ diff --git a/test/e2e/info_test.go b/test/e2e/info_test.go index fbcfb42828..5493a84b2d 100644 --- a/test/e2e/info_test.go +++ b/test/e2e/info_test.go @@ -244,6 +244,21 @@ var _ = Describe("Podman Info", func() { } }) + It("Podman info: check host.memAvailable is sane", func() { + session := podmanTest.PodmanExitCleanly("info", "--format", "{{.Host.MemTotal}} {{.Host.MemAvailable}}") + var total, avail int64 + _, err := fmt.Sscanf(session.OutputToString(), "%d %d", &total, &avail) + Expect(err).ToNot(HaveOccurred()) + + // On Linux, MemAvailable must always be reported; -1 is the + // sentinel used on platforms where the kernel doesn't expose + // this value. + Expect(avail).To(BeNumerically(">=", 0), "MemAvailable is supported (not the -1 'unknown' sentinel)") + + // MemAvailable (reclaimable memory included) can never exceed MemTotal. + Expect(avail).To(BeNumerically("<=", total), "MemAvailable does not exceed MemTotal") + }) + It("Podman info: check lock count", Serial, func() { // This should not run on architectures and OSes that use the file locks backend. // Which, for now, is Linux + RISCV and FreeBSD, neither of which are in CI - so diff --git a/test/system/005-info.bats b/test/system/005-info.bats index e56dcfce2c..7a645b9b6a 100644 --- a/test/system/005-info.bats +++ b/test/system/005-info.bats @@ -44,6 +44,9 @@ host.conmon.path | $expr_path host.conmon.package | .*conmon.* host.cgroupManager | \\\(systemd\\\|cgroupfs\\\) host.cgroupVersion | v[12] +host.memFree | [0-9]\\\+ +host.memAvailable | [0-9]\\\+ +host.memTotal | [0-9]\\\+ host.networkBackendInfo | .*dns.*package.* host.ociRuntime.path | $expr_path host.pasta | .*executable.*package.* @@ -62,6 +65,18 @@ store.imageStore.number | 1 done < <(parse_table "$tests") } +@test "podman info - host.memAvailable is sane" { + run_podman info --format '{{.Host.MemTotal}} {{.Host.MemAvailable}}' + read -r total avail <<<"$output" + + # On Linux, MemAvailable must always be reported; -1 is the sentinel + # used on platforms where the kernel doesn't expose this value. + assert "$avail" -ge 0 "MemAvailable is supported (not the -1 'unknown' sentinel)" + + # MemAvailable (reclaimable memory included) can never exceed MemTotal. + assert "$avail" -le "$total" "MemAvailable does not exceed MemTotal" +} + @test "podman info - confirm desired runtime" { if [[ -z "$CI_DESIRED_RUNTIME" ]]; then # When running in Cirrus, CI_DESIRED_RUNTIME *must* be defined