From 38b94668ea4bbc99deeb600ef8dfcbc400bd4c97 Mon Sep 17 00:00:00 2001 From: Antoine Toulme Date: Sat, 25 Mar 2023 23:14:49 -0700 Subject: [PATCH] allow to pass context values to override environment variables --- cpu/cpu_linux.go | 26 ++++++------ disk/disk_linux.go | 24 +++++------ docker/docker_linux.go | 30 +++++++------- docker/docker_notlinux.go | 4 +- host/host_linux.go | 70 ++++++++++++++++----------------- internal/common/common.go | 64 ++++++++++++++++++++++++++++++ internal/common/common_linux.go | 31 +++++++++------ internal/common/common_test.go | 44 ++++++++++++++++++++- load/load_linux.go | 18 ++++----- mem/mem_linux.go | 24 +++++------ mem/mem_linux_test.go | 7 ++-- net/net_linux.go | 24 +++++------ net/net_linux_test.go | 3 +- process/process_linux.go | 62 ++++++++++++++--------------- process/process_linux_test.go | 5 ++- process/process_posix.go | 4 +- process/process_solaris.go | 14 +++---- 17 files changed, 286 insertions(+), 168 deletions(-) diff --git a/cpu/cpu_linux.go b/cpu/cpu_linux.go index d4c575e80..1b64241ce 100644 --- a/cpu/cpu_linux.go +++ b/cpu/cpu_linux.go @@ -96,7 +96,7 @@ func Times(percpu bool) ([]TimesStat, error) { } func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { - filename := common.HostProc("stat") + filename := common.HostProcWithContext(ctx, "stat") lines := []string{} if percpu { statlines, err := common.ReadLines(filename) @@ -126,17 +126,17 @@ func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { return ret, nil } -func sysCPUPath(cpu int32, relPath string) string { - return common.HostSys(fmt.Sprintf("devices/system/cpu/cpu%d", cpu), relPath) +func sysCPUPath(ctx context.Context, cpu int32, relPath string) string { + return common.HostSysWithContext(ctx, fmt.Sprintf("devices/system/cpu/cpu%d", cpu), relPath) } -func finishCPUInfo(c *InfoStat) { +func finishCPUInfo(ctx context.Context, c *InfoStat) { var lines []string var err error var value float64 if len(c.CoreID) == 0 { - lines, err = common.ReadLines(sysCPUPath(c.CPU, "topology/core_id")) + lines, err = common.ReadLines(sysCPUPath(ctx, c.CPU, "topology/core_id")) if err == nil { c.CoreID = lines[0] } @@ -145,7 +145,7 @@ func finishCPUInfo(c *InfoStat) { // override the value of c.Mhz with cpufreq/cpuinfo_max_freq regardless // of the value from /proc/cpuinfo because we want to report the maximum // clock-speed of the CPU for c.Mhz, matching the behaviour of Windows - lines, err = common.ReadLines(sysCPUPath(c.CPU, "cpufreq/cpuinfo_max_freq")) + lines, err = common.ReadLines(sysCPUPath(ctx, c.CPU, "cpufreq/cpuinfo_max_freq")) // if we encounter errors below such as there are no cpuinfo_max_freq file, // we just ignore. so let Mhz is 0. if err != nil || len(lines) == 0 { @@ -173,7 +173,7 @@ func Info() ([]InfoStat, error) { } func InfoWithContext(ctx context.Context) ([]InfoStat, error) { - filename := common.HostProc("cpuinfo") + filename := common.HostProcWithContext(ctx, "cpuinfo") lines, _ := common.ReadLines(filename) var ret []InfoStat @@ -193,7 +193,7 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) { processorName = value case "processor", "cpu number": if c.CPU >= 0 { - finishCPUInfo(&c) + finishCPUInfo(ctx, &c) ret = append(ret, c) } c = InfoStat{Cores: 1, ModelName: processorName} @@ -301,7 +301,7 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) { } } if c.CPU >= 0 { - finishCPUInfo(&c) + finishCPUInfo(ctx, &c) ret = append(ret, c) } return ret, nil @@ -390,7 +390,7 @@ func CountsWithContext(ctx context.Context, logical bool) (int, error) { if logical { ret := 0 // https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_pslinux.py#L599 - procCpuinfo := common.HostProc("cpuinfo") + procCpuinfo := common.HostProcWithContext(ctx, "cpuinfo") lines, err := common.ReadLines(procCpuinfo) if err == nil { for _, line := range lines { @@ -404,7 +404,7 @@ func CountsWithContext(ctx context.Context, logical bool) (int, error) { } } if ret == 0 { - procStat := common.HostProc("stat") + procStat := common.HostProcWithContext(ctx, "stat") lines, err = common.ReadLines(procStat) if err != nil { return 0, err @@ -425,7 +425,7 @@ func CountsWithContext(ctx context.Context, logical bool) (int, error) { // https://github.com/giampaolo/psutil/pull/1727#issuecomment-707624964 // https://lkml.org/lkml/2019/2/26/41 for _, glob := range []string{"devices/system/cpu/cpu[0-9]*/topology/core_cpus_list", "devices/system/cpu/cpu[0-9]*/topology/thread_siblings_list"} { - if files, err := filepath.Glob(common.HostSys(glob)); err == nil { + if files, err := filepath.Glob(common.HostSysWithContext(ctx, glob)); err == nil { for _, file := range files { lines, err := common.ReadLines(file) if err != nil || len(lines) != 1 { @@ -440,7 +440,7 @@ func CountsWithContext(ctx context.Context, logical bool) (int, error) { } } // https://github.com/giampaolo/psutil/blob/122174a10b75c9beebe15f6c07dcf3afbe3b120d/psutil/_pslinux.py#L631-L652 - filename := common.HostProc("cpuinfo") + filename := common.HostProcWithContext(ctx, "cpuinfo") lines, err := common.ReadLines(filename) if err != nil { return 0, err diff --git a/disk/disk_linux.go b/disk/disk_linux.go index 14712f9ea..2a8c50ae4 100644 --- a/disk/disk_linux.go +++ b/disk/disk_linux.go @@ -260,10 +260,10 @@ func readMountFile(root string) (lines []string, useMounts bool, filename string func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) { // by default, try "/proc/1/..." first - root := common.HostProc(path.Join("1")) + root := common.HostProcWithContext(ctx, path.Join("1")) // force preference for dirname of HOST_PROC_MOUNTINFO, if set #1271 - hpmPath := os.Getenv("HOST_PROC_MOUNTINFO") + hpmPath := common.HostProcMountInfoWithContext(ctx) if hpmPath != "" { root = filepath.Dir(hpmPath) } @@ -274,13 +274,13 @@ func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, erro return nil, err } // fallback to "/proc/self/..." #1159 - lines, useMounts, filename, err = readMountFile(common.HostProc(path.Join("self"))) + lines, useMounts, filename, err = readMountFile(common.HostProcWithContext(ctx, path.Join("self"))) if err != nil { return nil, err } } - fs, err := getFileSystems() + fs, err := getFileSystems(ctx) if err != nil && !all { return nil, err } @@ -342,7 +342,7 @@ func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, erro } if strings.HasPrefix(d.Device, "/dev/mapper/") { - devpath, err := filepath.EvalSymlinks(common.HostDev(strings.Replace(d.Device, "/dev", "", 1))) + devpath, err := filepath.EvalSymlinks(common.HostDevWithContext(ctx, strings.Replace(d.Device, "/dev", "", 1))) if err == nil { d.Device = devpath } @@ -351,7 +351,7 @@ func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, erro // /dev/root is not the real device name // so we get the real device name from its major/minor number if d.Device == "/dev/root" { - devpath, err := os.Readlink(common.HostSys("/dev/block/" + blockDeviceID)) + devpath, err := os.Readlink(common.HostSysWithContext(ctx, "/dev/block/"+blockDeviceID)) if err == nil { d.Device = strings.Replace(d.Device, "root", filepath.Base(devpath), 1) } @@ -364,8 +364,8 @@ func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, erro } // getFileSystems returns supported filesystems from /proc/filesystems -func getFileSystems() ([]string, error) { - filename := common.HostProc("filesystems") +func getFileSystems(ctx context.Context) ([]string, error) { + filename := common.HostProcWithContext(ctx, "filesystems") lines, err := common.ReadLines(filename) if err != nil { return nil, err @@ -387,7 +387,7 @@ func getFileSystems() ([]string, error) { } func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) { - filename := common.HostProc("diskstats") + filename := common.HostProcWithContext(ctx, "diskstats") lines, err := common.ReadLines(filename) if err != nil { return nil, err @@ -492,7 +492,7 @@ func SerialNumberWithContext(ctx context.Context, name string) (string, error) { minor := unix.Minor(uint64(stat.Rdev)) // Try to get the serial from udev data - udevDataPath := common.HostRun(fmt.Sprintf("udev/data/b%d:%d", major, minor)) + udevDataPath := common.HostRunWithContext(ctx, fmt.Sprintf("udev/data/b%d:%d", major, minor)) if udevdata, err := ioutil.ReadFile(udevDataPath); err == nil { scanner := bufio.NewScanner(bytes.NewReader(udevdata)) for scanner.Scan() { @@ -505,7 +505,7 @@ func SerialNumberWithContext(ctx context.Context, name string) (string, error) { // Try to get the serial from sysfs, look at the disk device (minor 0) directly // because if it is a partition it is not going to contain any device information - devicePath := common.HostSys(fmt.Sprintf("dev/block/%d:0/device", major)) + devicePath := common.HostSysWithContext(ctx, fmt.Sprintf("dev/block/%d:0/device", major)) model, _ := ioutil.ReadFile(filepath.Join(devicePath, "model")) serial, _ := ioutil.ReadFile(filepath.Join(devicePath, "serial")) if len(model) > 0 && len(serial) > 0 { @@ -516,7 +516,7 @@ func SerialNumberWithContext(ctx context.Context, name string) (string, error) { func LabelWithContext(ctx context.Context, name string) (string, error) { // Try label based on devicemapper name - dmname_filename := common.HostSys(fmt.Sprintf("block/%s/dm/name", name)) + dmname_filename := common.HostSysWithContext(ctx, fmt.Sprintf("block/%s/dm/name", name)) if !common.PathExists(dmname_filename) { return "", nil diff --git a/docker/docker_linux.go b/docker/docker_linux.go index ac7cc9809..4904874d0 100644 --- a/docker/docker_linux.go +++ b/docker/docker_linux.go @@ -100,7 +100,7 @@ func CgroupCPUUsage(containerID string, base string) (float64, error) { } func CgroupCPUWithContext(ctx context.Context, containerID string, base string) (*CgroupCPUStat, error) { - statfile := getCgroupFilePath(containerID, base, "cpuacct", "cpuacct.stat") + statfile := getCgroupFilePath(ctx, containerID, base, "cpuacct", "cpuacct.stat") lines, err := common.ReadLines(statfile) if err != nil { return nil, err @@ -136,7 +136,7 @@ func CgroupCPUWithContext(ctx context.Context, containerID string, base string) } func CgroupCPUUsageWithContext(ctx context.Context, containerID, base string) (float64, error) { - usagefile := getCgroupFilePath(containerID, base, "cpuacct", "cpuacct.usage") + usagefile := getCgroupFilePath(ctx, containerID, base, "cpuacct", "cpuacct.usage") lines, err := common.ReadLinesOffsetN(usagefile, 0, 1) if err != nil { return 0.0, err @@ -159,11 +159,11 @@ func CgroupCPUUsageDocker(containerid string) (float64, error) { } func CgroupCPUDockerWithContext(ctx context.Context, containerid string) (*CgroupCPUStat, error) { - return CgroupCPUWithContext(ctx, containerid, common.HostSys("fs/cgroup/cpuacct/docker")) + return CgroupCPUWithContext(ctx, containerid, common.HostSysWithContext(ctx, "fs/cgroup/cpuacct/docker")) } func CgroupCPUDockerUsageWithContext(ctx context.Context, containerid string) (float64, error) { - return CgroupCPUUsageWithContext(ctx, containerid, common.HostSys("fs/cgroup/cpuacct/docker")) + return CgroupCPUUsageWithContext(ctx, containerid, common.HostSysWithContext(ctx, "fs/cgroup/cpuacct/docker")) } func CgroupMem(containerID string, base string) (*CgroupMemStat, error) { @@ -171,7 +171,7 @@ func CgroupMem(containerID string, base string) (*CgroupMemStat, error) { } func CgroupMemWithContext(ctx context.Context, containerID string, base string) (*CgroupMemStat, error) { - statfile := getCgroupFilePath(containerID, base, "memory", "memory.stat") + statfile := getCgroupFilePath(ctx, containerID, base, "memory", "memory.stat") // empty containerID means all cgroup if len(containerID) == 0 { @@ -246,19 +246,19 @@ func CgroupMemWithContext(ctx context.Context, containerID string, base string) } } - r, err := getCgroupMemFile(containerID, base, "memory.usage_in_bytes") + r, err := getCgroupMemFile(ctx, containerID, base, "memory.usage_in_bytes") if err == nil { ret.MemUsageInBytes = r } - r, err = getCgroupMemFile(containerID, base, "memory.max_usage_in_bytes") + r, err = getCgroupMemFile(ctx, containerID, base, "memory.max_usage_in_bytes") if err == nil { ret.MemMaxUsageInBytes = r } - r, err = getCgroupMemFile(containerID, base, "memory.limit_in_bytes") + r, err = getCgroupMemFile(ctx, containerID, base, "memory.limit_in_bytes") if err == nil { ret.MemLimitInBytes = r } - r, err = getCgroupMemFile(containerID, base, "memory.failcnt") + r, err = getCgroupMemFile(ctx, containerID, base, "memory.failcnt") if err == nil { ret.MemFailCnt = r } @@ -271,27 +271,27 @@ func CgroupMemDocker(containerID string) (*CgroupMemStat, error) { } func CgroupMemDockerWithContext(ctx context.Context, containerID string) (*CgroupMemStat, error) { - return CgroupMemWithContext(ctx, containerID, common.HostSys("fs/cgroup/memory/docker")) + return CgroupMemWithContext(ctx, containerID, common.HostSysWithContext(ctx, "fs/cgroup/memory/docker")) } // getCgroupFilePath constructs file path to get targeted stats file. -func getCgroupFilePath(containerID, base, target, file string) string { +func getCgroupFilePath(ctx context.Context, containerID, base, target, file string) string { if len(base) == 0 { - base = common.HostSys(fmt.Sprintf("fs/cgroup/%s/docker", target)) + base = common.HostSysWithContext(ctx, fmt.Sprintf("fs/cgroup/%s/docker", target)) } statfile := path.Join(base, containerID, file) if _, err := os.Stat(statfile); os.IsNotExist(err) { statfile = path.Join( - common.HostSys(fmt.Sprintf("fs/cgroup/%s/system.slice", target)), "docker-"+containerID+".scope", file) + common.HostSysWithContext(ctx, fmt.Sprintf("fs/cgroup/%s/system.slice", target)), "docker-"+containerID+".scope", file) } return statfile } // getCgroupMemFile reads a cgroup file and return the contents as uint64. -func getCgroupMemFile(containerID, base, file string) (uint64, error) { - statfile := getCgroupFilePath(containerID, base, "memory", file) +func getCgroupMemFile(ctx context.Context, containerID, base, file string) (uint64, error) { + statfile := getCgroupFilePath(ctx, containerID, base, "memory", file) lines, err := common.ReadLines(statfile) if err != nil { return 0, err diff --git a/docker/docker_notlinux.go b/docker/docker_notlinux.go index 2bd91110b..1e3821b93 100644 --- a/docker/docker_notlinux.go +++ b/docker/docker_notlinux.go @@ -46,7 +46,7 @@ func CgroupCPUDocker(containerid string) (*CgroupCPUStat, error) { } func CgroupCPUDockerWithContext(ctx context.Context, containerid string) (*CgroupCPUStat, error) { - return CgroupCPU(containerid, common.HostSys("fs/cgroup/cpuacct/docker")) + return CgroupCPU(containerid, common.HostSysWithContext(ctx, "fs/cgroup/cpuacct/docker")) } func CgroupMem(containerid string, base string) (*CgroupMemStat, error) { @@ -62,5 +62,5 @@ func CgroupMemDocker(containerid string) (*CgroupMemStat, error) { } func CgroupMemDockerWithContext(ctx context.Context, containerid string) (*CgroupMemStat, error) { - return CgroupMem(containerid, common.HostSys("fs/cgroup/memory/docker")) + return CgroupMem(containerid, common.HostSysWithContext(ctx, "fs/cgroup/memory/docker")) } diff --git a/host/host_linux.go b/host/host_linux.go index adce92e2f..62a4b3ca9 100644 --- a/host/host_linux.go +++ b/host/host_linux.go @@ -35,9 +35,9 @@ const ( ) func HostIDWithContext(ctx context.Context) (string, error) { - sysProductUUID := common.HostSys("class/dmi/id/product_uuid") - machineID := common.HostEtc("machine-id") - procSysKernelRandomBootID := common.HostProc("sys/kernel/random/boot_id") + sysProductUUID := common.HostSysWithContext(ctx, "class/dmi/id/product_uuid") + machineID := common.HostEtcWithContext(ctx, "machine-id") + procSysKernelRandomBootID := common.HostProcWithContext(ctx, "sys/kernel/random/boot_id") switch { // In order to read this file, needs to be supported by kernel/arch and run as root // so having fallback is important @@ -67,7 +67,7 @@ func HostIDWithContext(ctx context.Context) (string, error) { } func numProcs(ctx context.Context) (uint64, error) { - return common.NumProcs() + return common.NumProcsWithContext(ctx) } func BootTimeWithContext(ctx context.Context) (uint64, error) { @@ -83,7 +83,7 @@ func UptimeWithContext(ctx context.Context) (uint64, error) { } func UsersWithContext(ctx context.Context) ([]UserStat, error) { - utmpfile := common.HostVar("run/utmp") + utmpfile := common.HostVarWithContext(ctx, "run/utmp") file, err := os.Open(utmpfile) if err != nil { @@ -124,10 +124,10 @@ func UsersWithContext(ctx context.Context) ([]UserStat, error) { return ret, nil } -func getlsbStruct() (*lsbStruct, error) { +func getlsbStruct(ctx context.Context) (*lsbStruct, error) { ret := &lsbStruct{} - if common.PathExists(common.HostEtc("lsb-release")) { - contents, err := common.ReadLines(common.HostEtc("lsb-release")) + if common.PathExists(common.HostEtcWithContext(ctx, "lsb-release")) { + contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "lsb-release")) if err != nil { return ret, err // return empty } @@ -175,31 +175,31 @@ func getlsbStruct() (*lsbStruct, error) { } func PlatformInformationWithContext(ctx context.Context) (platform string, family string, version string, err error) { - lsb, err := getlsbStruct() + lsb, err := getlsbStruct(ctx) if err != nil { lsb = &lsbStruct{} } - if common.PathExistsWithContents(common.HostEtc("oracle-release")) { + if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "oracle-release")) { platform = "oracle" - contents, err := common.ReadLines(common.HostEtc("oracle-release")) + contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "oracle-release")) if err == nil { version = getRedhatishVersion(contents) } - } else if common.PathExistsWithContents(common.HostEtc("enterprise-release")) { + } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "enterprise-release")) { platform = "oracle" - contents, err := common.ReadLines(common.HostEtc("enterprise-release")) + contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "enterprise-release")) if err == nil { version = getRedhatishVersion(contents) } - } else if common.PathExistsWithContents(common.HostEtc("slackware-version")) { + } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "slackware-version")) { platform = "slackware" - contents, err := common.ReadLines(common.HostEtc("slackware-version")) + contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "slackware-version")) if err == nil { version = getSlackwareVersion(contents) } - } else if common.PathExistsWithContents(common.HostEtc("debian_version")) { + } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "debian_version")) { if lsb.ID == "Ubuntu" { platform = "ubuntu" version = lsb.Release @@ -218,53 +218,53 @@ func PlatformInformationWithContext(ctx context.Context) (platform string, famil } else { platform = "debian" } - contents, err := common.ReadLines(common.HostEtc("debian_version")) + contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "debian_version")) if err == nil && len(contents) > 0 && contents[0] != "" { version = contents[0] } } - } else if common.PathExists(common.HostEtc("neokylin-release")) { - contents, err := common.ReadLines(common.HostEtc("neokylin-release")) + } else if common.PathExists(common.HostEtcWithContext(ctx, "neokylin-release")) { + contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "neokylin-release")) if err == nil { version = getRedhatishVersion(contents) platform = getRedhatishPlatform(contents) } - } else if common.PathExists(common.HostEtc("redhat-release")) { - contents, err := common.ReadLines(common.HostEtc("redhat-release")) + } else if common.PathExists(common.HostEtcWithContext(ctx, "redhat-release")) { + contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "redhat-release")) if err == nil { version = getRedhatishVersion(contents) platform = getRedhatishPlatform(contents) } - } else if common.PathExists(common.HostEtc("system-release")) { - contents, err := common.ReadLines(common.HostEtc("system-release")) + } else if common.PathExists(common.HostEtcWithContext(ctx, "system-release")) { + contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "system-release")) if err == nil { version = getRedhatishVersion(contents) platform = getRedhatishPlatform(contents) } - } else if common.PathExists(common.HostEtc("gentoo-release")) { + } else if common.PathExists(common.HostEtcWithContext(ctx, "gentoo-release")) { platform = "gentoo" - contents, err := common.ReadLines(common.HostEtc("gentoo-release")) + contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "gentoo-release")) if err == nil { version = getRedhatishVersion(contents) } - } else if common.PathExists(common.HostEtc("SuSE-release")) { - contents, err := common.ReadLines(common.HostEtc("SuSE-release")) + } else if common.PathExists(common.HostEtcWithContext(ctx, "SuSE-release")) { + contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "SuSE-release")) if err == nil { version = getSuseVersion(contents) platform = getSusePlatform(contents) } // TODO: slackware detecion - } else if common.PathExists(common.HostEtc("arch-release")) { + } else if common.PathExists(common.HostEtcWithContext(ctx, "arch-release")) { platform = "arch" version = lsb.Release - } else if common.PathExists(common.HostEtc("alpine-release")) { + } else if common.PathExists(common.HostEtcWithContext(ctx, "alpine-release")) { platform = "alpine" - contents, err := common.ReadLines(common.HostEtc("alpine-release")) + contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "alpine-release")) if err == nil && len(contents) > 0 && contents[0] != "" { version = contents[0] } - } else if common.PathExists(common.HostEtc("os-release")) { - p, v, err := common.GetOSRelease() + } else if common.PathExists(common.HostEtcWithContext(ctx, "os-release")) { + p, v, err := common.GetOSReleaseWithContext(ctx) if err == nil { platform = p version = v @@ -390,14 +390,14 @@ func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, err // Only the temp*_input file provides current temperature // value in millidegree Celsius as reported by the temperature to the device: // https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface - if files, err = filepath.Glob(common.HostSys("/class/hwmon/hwmon*/temp*_input")); err != nil { + if files, err = filepath.Glob(common.HostSysWithContext(ctx, "/class/hwmon/hwmon*/temp*_input")); err != nil { return temperatures, err } if len(files) == 0 { // CentOS has an intermediate /device directory: // https://github.com/giampaolo/psutil/issues/971 - if files, err = filepath.Glob(common.HostSys("/class/hwmon/hwmon*/device/temp*_input")); err != nil { + if files, err = filepath.Glob(common.HostSysWithContext(ctx, "/class/hwmon/hwmon*/device/temp*_input")); err != nil { return temperatures, err } } @@ -405,7 +405,7 @@ func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, err var warns Warnings if len(files) == 0 { // handle distributions without hwmon, like raspbian #391, parse legacy thermal_zone files - files, err = filepath.Glob(common.HostSys("/class/thermal/thermal_zone*/")) + files, err = filepath.Glob(common.HostSysWithContext(ctx, "/class/thermal/thermal_zone*/")) if err != nil { return temperatures, err } diff --git a/internal/common/common.go b/internal/common/common.go index c1e96ca7d..33937d015 100644 --- a/internal/common/common.go +++ b/internal/common/common.go @@ -32,6 +32,10 @@ var ( ErrTimeout = errors.New("command timed out") ) +type envKey string + +var Env = envKey("string") + type Invoker interface { Command(string, ...string) ([]byte, error) CommandWithContext(context.Context, string, ...string) ([]byte, error) @@ -321,6 +325,23 @@ func PathExistsWithContents(filename string) bool { return info.Size() > 4 // at least 4 bytes } +// GetEnvWithContext retrieves the environment variable key. If it does not exist it returns the default. +// The context may optionally contain a map superseding os.Env. +func GetEnvWithContext(ctx context.Context, key string, dfault string, combineWith ...string) string { + var value string + if env, ok := ctx.Value(Env).(map[string]string); ok { + value = env[key] + } + if value == "" { + value = os.Getenv(key) + } + if value == "" { + value = dfault + } + + return combine(value, combineWith) +} + // GetEnv retrieves the environment variable key. If it does not exist it returns the default. func GetEnv(key string, dfault string, combineWith ...string) string { value := os.Getenv(key) @@ -328,6 +349,10 @@ func GetEnv(key string, dfault string, combineWith ...string) string { value = dfault } + return combine(value, combineWith) +} + +func combine(value string, combineWith []string) string { switch len(combineWith) { case 0: return value @@ -341,34 +366,73 @@ func GetEnv(key string, dfault string, combineWith ...string) string { } } +// Deprecated: use HostProcWithContext instead func HostProc(combineWith ...string) string { return GetEnv("HOST_PROC", "/proc", combineWith...) } +// Deprecated: use HostSysWithContext instead func HostSys(combineWith ...string) string { return GetEnv("HOST_SYS", "/sys", combineWith...) } +// Deprecated: use HostEtcWithContext instead func HostEtc(combineWith ...string) string { return GetEnv("HOST_ETC", "/etc", combineWith...) } +// Deprecated: use HostVarWithContext instead func HostVar(combineWith ...string) string { return GetEnv("HOST_VAR", "/var", combineWith...) } +// Deprecated: use HostRunWithContext instead func HostRun(combineWith ...string) string { return GetEnv("HOST_RUN", "/run", combineWith...) } +// Deprecated: use HostDevWithContext instead func HostDev(combineWith ...string) string { return GetEnv("HOST_DEV", "/dev", combineWith...) } +// Deprecated: use HostRootWithContext instead func HostRoot(combineWith ...string) string { return GetEnv("HOST_ROOT", "/", combineWith...) } +func HostProcWithContext(ctx context.Context, combineWith ...string) string { + return GetEnvWithContext(ctx, "HOST_PROC", "/proc", combineWith...) +} + +func HostProcMountInfoWithContext(ctx context.Context, combineWith ...string) string { + return GetEnvWithContext(ctx, "HOST_PROC_MOUNTINFO", "", combineWith...) +} + +func HostSysWithContext(ctx context.Context, combineWith ...string) string { + return GetEnvWithContext(ctx, "HOST_SYS", "/sys", combineWith...) +} + +func HostEtcWithContext(ctx context.Context, combineWith ...string) string { + return GetEnvWithContext(ctx, "HOST_ETC", "/etc", combineWith...) +} + +func HostVarWithContext(ctx context.Context, combineWith ...string) string { + return GetEnvWithContext(ctx, "HOST_VAR", "/var", combineWith...) +} + +func HostRunWithContext(ctx context.Context, combineWith ...string) string { + return GetEnvWithContext(ctx, "HOST_RUN", "/run", combineWith...) +} + +func HostDevWithContext(ctx context.Context, combineWith ...string) string { + return GetEnvWithContext(ctx, "HOST_DEV", "/dev", combineWith...) +} + +func HostRootWithContext(ctx context.Context, combineWith ...string) string { + return GetEnvWithContext(ctx, "HOST_ROOT", "/", combineWith...) +} + // getSysctrlEnv sets LC_ALL=C in a list of env vars for use when running // sysctl commands (see DoSysctrl). func getSysctrlEnv(env []string) []string { diff --git a/internal/common/common_linux.go b/internal/common/common_linux.go index fa6373b55..9c9088d14 100644 --- a/internal/common/common_linux.go +++ b/internal/common/common_linux.go @@ -30,8 +30,13 @@ func DoSysctrl(mib string) ([]string, error) { return values, nil } +// Deprecated: use NumProcsWithContext instead func NumProcs() (uint64, error) { - f, err := os.Open(HostProc()) + return NumProcsWithContext(context.Background()) +} + +func NumProcsWithContext(ctx context.Context) (uint64, error) { + f, err := os.Open(HostProcWithContext(ctx)) if err != nil { return 0, err } @@ -67,7 +72,7 @@ func BootTimeWithContext(ctx context.Context) (uint64, error) { statFile = "uptime" } - filename := HostProc(statFile) + filename := HostProcWithContext(ctx, statFile) lines, err := ReadLines(filename) if os.IsPermission(err) { var info syscall.Sysinfo_t @@ -139,7 +144,7 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) { } cachedVirtMutex.RUnlock() - filename := HostProc("xen") + filename := HostProcWithContext(ctx, "xen") if PathExists(filename) { system = "xen" role = "guest" // assume guest @@ -154,7 +159,7 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) { } } - filename = HostProc("modules") + filename = HostProcWithContext(ctx, "modules") if PathExists(filename) { contents, err := ReadLines(filename) if err == nil { @@ -177,7 +182,7 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) { } } - filename = HostProc("cpuinfo") + filename = HostProcWithContext(ctx, "cpuinfo") if PathExists(filename) { contents, err := ReadLines(filename) if err == nil { @@ -190,7 +195,7 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) { } } - filename = HostProc("bus/pci/devices") + filename = HostProcWithContext(ctx, "bus/pci/devices") if PathExists(filename) { contents, err := ReadLines(filename) if err == nil { @@ -200,7 +205,7 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) { } } - filename = HostProc() + filename = HostProcWithContext(ctx) if PathExists(filepath.Join(filename, "bc", "0")) { system = "openvz" role = "host" @@ -251,15 +256,15 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) { } } - if PathExists(HostEtc("os-release")) { - p, _, err := GetOSRelease() + if PathExists(HostEtcWithContext(ctx, "os-release")) { + p, _, err := GetOSReleaseWithContext(ctx) if err == nil && p == "coreos" { system = "rkt" // Is it true? role = "host" } } - if PathExists(HostRoot(".dockerenv")) { + if PathExists(HostRootWithContext(ctx, ".dockerenv")) { system = "docker" role = "guest" } @@ -278,7 +283,11 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) { } func GetOSRelease() (platform string, version string, err error) { - contents, err := ReadLines(HostEtc("os-release")) + return GetOSReleaseWithContext(context.Background()) +} + +func GetOSReleaseWithContext(ctx context.Context) (platform string, version string, err error) { + contents, err := ReadLines(HostEtcWithContext(ctx, "os-release")) if err != nil { return "", "", nil // return empty } diff --git a/internal/common/common_test.go b/internal/common/common_test.go index 27bcfac06..e216b18c1 100644 --- a/internal/common/common_test.go +++ b/internal/common/common_test.go @@ -1,6 +1,7 @@ package common import ( + "context" "fmt" "os" "reflect" @@ -125,7 +126,7 @@ func TestHostEtc(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("windows doesn't have etc") } - p := HostEtc("mtab") + p := HostEtcWithContext(context.Background(), "mtab") if p != "/etc/mtab" { t.Errorf("invalid HostEtc, %s", p) } @@ -160,3 +161,44 @@ func TestGetSysctrlEnv(t *testing.T) { t.Errorf("unexpected real result from getSysctrlEnv: %q", env) } } + +func TestGetEnvDefault(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("windows doesn't have etc") + } + p := HostEtcWithContext(context.Background(), "mtab") + if p != "/etc/mtab" { + t.Errorf("invalid HostEtc, %s", p) + } +} + +func TestGetEnvWithNoContext(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("windows doesn't have etc") + } + old := os.Getenv("HOST_ETC") + os.Setenv("HOST_ETC", "/bar") + defer func() { + os.Setenv("HOST_ETC", old) + }() + p := HostEtcWithContext(context.Background(), "mtab") + if p != "/bar/mtab" { + t.Errorf("invalid HostEtc, %s", p) + } +} + +func TestGetEnvWithContextOverride(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("windows doesn't have etc") + } + old := os.Getenv("HOST_ETC") + os.Setenv("HOST_ETC", "/bar") + defer func() { + os.Setenv("HOST_ETC", old) + }() + ctx := context.WithValue(context.Background(), Env, map[string]string{"HOST_ETC": "/foo"}) + p := HostEtcWithContext(ctx, "mtab") + if p != "/foo/mtab" { + t.Errorf("invalid HostEtc, %s", p) + } +} diff --git a/load/load_linux.go b/load/load_linux.go index debf0733c..0298c8bed 100644 --- a/load/load_linux.go +++ b/load/load_linux.go @@ -18,7 +18,7 @@ func Avg() (*AvgStat, error) { } func AvgWithContext(ctx context.Context) (*AvgStat, error) { - stat, err := fileAvgWithContext() + stat, err := fileAvgWithContext(ctx) if err != nil { stat, err = sysinfoAvgWithContext() } @@ -40,8 +40,8 @@ func sysinfoAvgWithContext() (*AvgStat, error) { }, nil } -func fileAvgWithContext() (*AvgStat, error) { - values, err := readLoadAvgFromFile() +func fileAvgWithContext(ctx context.Context) (*AvgStat, error) { + values, err := readLoadAvgFromFile(ctx) if err != nil { return nil, err } @@ -75,7 +75,7 @@ func Misc() (*MiscStat, error) { } func MiscWithContext(ctx context.Context) (*MiscStat, error) { - filename := common.HostProc("stat") + filename := common.HostProcWithContext(ctx, "stat") out, err := ioutil.ReadFile(filename) if err != nil { return nil, err @@ -107,7 +107,7 @@ func MiscWithContext(ctx context.Context) (*MiscStat, error) { } - procsTotal, err := getProcsTotal() + procsTotal, err := getProcsTotal(ctx) if err != nil { return ret, err } @@ -116,16 +116,16 @@ func MiscWithContext(ctx context.Context) (*MiscStat, error) { return ret, nil } -func getProcsTotal() (int64, error) { - values, err := readLoadAvgFromFile() +func getProcsTotal(ctx context.Context) (int64, error) { + values, err := readLoadAvgFromFile(ctx) if err != nil { return 0, err } return strconv.ParseInt(strings.Split(values[3], "/")[1], 10, 64) } -func readLoadAvgFromFile() ([]string, error) { - loadavgFilename := common.HostProc("loadavg") +func readLoadAvgFromFile(ctx context.Context) ([]string, error) { + loadavgFilename := common.HostProcWithContext(ctx, "loadavg") line, err := ioutil.ReadFile(loadavgFilename) if err != nil { return nil, err diff --git a/mem/mem_linux.go b/mem/mem_linux.go index 059518dc5..361d06bcc 100644 --- a/mem/mem_linux.go +++ b/mem/mem_linux.go @@ -37,7 +37,7 @@ func VirtualMemory() (*VirtualMemoryStat, error) { } func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) { - vm, _, err := fillFromMeminfoWithContext() + vm, _, err := fillFromMeminfoWithContext(ctx) if err != nil { return nil, err } @@ -49,15 +49,15 @@ func VirtualMemoryEx() (*VirtualMemoryExStat, error) { } func VirtualMemoryExWithContext(ctx context.Context) (*VirtualMemoryExStat, error) { - _, vmEx, err := fillFromMeminfoWithContext() + _, vmEx, err := fillFromMeminfoWithContext(ctx) if err != nil { return nil, err } return vmEx, nil } -func fillFromMeminfoWithContext() (*VirtualMemoryStat, *VirtualMemoryExStat, error) { - filename := common.HostProc("meminfo") +func fillFromMeminfoWithContext(ctx context.Context) (*VirtualMemoryStat, *VirtualMemoryExStat, error) { + filename := common.HostProcWithContext(ctx, "meminfo") lines, _ := common.ReadLines(filename) // flag if MemAvailable is in /proc/meminfo (kernel 3.14+) @@ -318,7 +318,7 @@ func fillFromMeminfoWithContext() (*VirtualMemoryStat, *VirtualMemoryExStat, err if !memavail { if activeFile && inactiveFile && sReclaimable { - ret.Available = calculateAvailVmem(ret, retEx) + ret.Available = calculateAvailVmem(ctx, ret, retEx) } else { ret.Available = ret.Cached + ret.Free } @@ -351,7 +351,7 @@ func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) { } else { ret.UsedPercent = 0 } - filename := common.HostProc("vmstat") + filename := common.HostProcWithContext(ctx, "vmstat") lines, _ := common.ReadLines(filename) for _, l := range lines { fields := strings.Fields(l) @@ -403,10 +403,10 @@ func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) { // calculateAvailVmem is a fallback under kernel 3.14 where /proc/meminfo does not provide // "MemAvailable:" column. It reimplements an algorithm from the link below // https://github.com/giampaolo/psutil/pull/890 -func calculateAvailVmem(ret *VirtualMemoryStat, retEx *VirtualMemoryExStat) uint64 { +func calculateAvailVmem(ctx context.Context, ret *VirtualMemoryStat, retEx *VirtualMemoryExStat) uint64 { var watermarkLow uint64 - fn := common.HostProc("zoneinfo") + fn := common.HostProcWithContext(ctx, "zoneinfo") lines, err := common.ReadLines(fn) if err != nil { return ret.Free + ret.Cached // fallback under kernel 2.6.13 @@ -458,18 +458,18 @@ func SwapDevices() ([]*SwapDevice, error) { } func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) { - swapsFilePath := common.HostProc(swapsFilename) + swapsFilePath := common.HostProcWithContext(ctx, swapsFilename) f, err := os.Open(swapsFilePath) if err != nil { return nil, err } defer f.Close() - return parseSwapsFile(f) + return parseSwapsFile(ctx, f) } -func parseSwapsFile(r io.Reader) ([]*SwapDevice, error) { - swapsFilePath := common.HostProc(swapsFilename) +func parseSwapsFile(ctx context.Context, r io.Reader) ([]*SwapDevice, error) { + swapsFilePath := common.HostProcWithContext(ctx, swapsFilename) scanner := bufio.NewScanner(r) if !scanner.Scan() { if err := scanner.Err(); err != nil { diff --git a/mem/mem_linux_test.go b/mem/mem_linux_test.go index a0590c961..d830fbf9c 100644 --- a/mem/mem_linux_test.go +++ b/mem/mem_linux_test.go @@ -4,6 +4,7 @@ package mem import ( + "context" "path/filepath" "reflect" "strings" @@ -138,7 +139,7 @@ const invalidFile = `INVALID Type Size Used Priority func TestParseSwapsFile_ValidFile(t *testing.T) { assert := assert.New(t) - stats, err := parseSwapsFile(strings.NewReader(validFile)) + stats, err := parseSwapsFile(context.Background(), strings.NewReader(validFile)) assert.NoError(err) assert.Equal(*stats[0], SwapDevice{ @@ -155,11 +156,11 @@ func TestParseSwapsFile_ValidFile(t *testing.T) { } func TestParseSwapsFile_InvalidFile(t *testing.T) { - _, err := parseSwapsFile(strings.NewReader(invalidFile)) + _, err := parseSwapsFile(context.Background(), strings.NewReader(invalidFile)) assert.Error(t, err) } func TestParseSwapsFile_EmptyFile(t *testing.T) { - _, err := parseSwapsFile(strings.NewReader("")) + _, err := parseSwapsFile(context.Background(), strings.NewReader("")) assert.Error(t, err) } diff --git a/net/net_linux.go b/net/net_linux.go index dd62d4791..de0ea7345 100644 --- a/net/net_linux.go +++ b/net/net_linux.go @@ -50,7 +50,7 @@ func IOCounters(pernic bool) ([]IOCountersStat, error) { } func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) { - filename := common.HostProc("net/dev") + filename := common.HostProcWithContext(ctx, "net/dev") return IOCountersByFileWithContext(ctx, pernic, filename) } @@ -177,7 +177,7 @@ func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoC protos[p] = true } - filename := common.HostProc("net/snmp") + filename := common.HostProcWithContext(ctx, "net/snmp") lines, err := common.ReadLines(filename) if err != nil { return nil, err @@ -230,8 +230,8 @@ func FilterCounters() ([]FilterStat, error) { } func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) { - countfile := common.HostProc("sys/net/netfilter/nf_conntrack_count") - maxfile := common.HostProc("sys/net/netfilter/nf_conntrack_max") + countfile := common.HostProcWithContext(ctx, "sys/net/netfilter/nf_conntrack_count") + maxfile := common.HostProcWithContext(ctx, "sys/net/netfilter/nf_conntrack_max") count, err := common.ReadInts(countfile) if err != nil { @@ -260,7 +260,7 @@ func ConntrackStats(percpu bool) ([]ConntrackStat, error) { // ConntrackStatsWithContext returns more detailed info about the conntrack table func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) { - return conntrackStatsFromFile(common.HostProc("net/stat/nf_conntrack"), percpu) + return conntrackStatsFromFile(common.HostProcWithContext(ctx, "net/stat/nf_conntrack"), percpu) } // conntrackStatsFromFile returns more detailed info about the conntrack table @@ -459,7 +459,7 @@ func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, p if !ok { return nil, fmt.Errorf("invalid kind, %s", kind) } - root := common.HostProc() + root := common.HostProcWithContext(ctx) var err error var inodes map[string][]inodeMap if pid == 0 { @@ -531,7 +531,7 @@ func statsFromInodesWithContext(ctx context.Context, root string, pid int32, tma if !skipUids { // fetch process owner Real, effective, saved set, and filesystem UIDs proc := process{Pid: conn.Pid} - conn.Uids, _ = proc.getUids() + conn.Uids, _ = proc.getUids(ctx) } ret = append(ret, conn) @@ -599,7 +599,7 @@ func Pids() ([]int32, error) { func PidsWithContext(ctx context.Context) ([]int32, error) { var ret []int32 - d, err := os.Open(common.HostProc()) + d, err := os.Open(common.HostProcWithContext(ctx)) if err != nil { return nil, err } @@ -631,8 +631,8 @@ type process struct { } // Uids returns user ids of the process as a slice of the int -func (p *process) getUids() ([]int32, error) { - err := p.fillFromStatus() +func (p *process) getUids(ctx context.Context) ([]int32, error) { + err := p.fillFromStatus(ctx) if err != nil { return []int32{}, err } @@ -640,9 +640,9 @@ func (p *process) getUids() ([]int32, error) { } // Get status from /proc/(pid)/status -func (p *process) fillFromStatus() error { +func (p *process) fillFromStatus(ctx context.Context) error { pid := p.Pid - statPath := common.HostProc(strconv.Itoa(int(pid)), "status") + statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "status") contents, err := ioutil.ReadFile(statPath) if err != nil { return err diff --git a/net/net_linux_test.go b/net/net_linux_test.go index 61f7e5a76..f1b7fbaa7 100644 --- a/net/net_linux_test.go +++ b/net/net_linux_test.go @@ -1,6 +1,7 @@ package net import ( + "context" "fmt" "io/ioutil" "net" @@ -101,7 +102,7 @@ func TestGetProcInodesAll(t *testing.T) { }() <-waitForServer - root := common.HostProc("") + root := common.HostProcWithContext(context.Background(), "") v, err := getProcInodesAll(root, 0) assert.Nil(t, err) assert.NotEmpty(t, v) diff --git a/process/process_linux.go b/process/process_linux.go index 6dbef4c2f..29c447390 100644 --- a/process/process_linux.go +++ b/process/process_linux.go @@ -101,7 +101,7 @@ func (p *Process) TgidWithContext(ctx context.Context) (int32, error) { } func (p *Process) ExeWithContext(ctx context.Context) (string, error) { - return p.fillFromExeWithContext() + return p.fillFromExeWithContext(ctx) } func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { @@ -121,7 +121,7 @@ func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { } func (p *Process) CwdWithContext(ctx context.Context) (string, error) { - return p.fillFromCwdWithContext() + return p.fillFromCwdWithContext(ctx) } func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) { @@ -135,7 +135,7 @@ func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) { func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details pid := p.Pid - statPath := common.HostProc(strconv.Itoa(int(pid)), "stat") + statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "stat") contents, err := ioutil.ReadFile(statPath) if err != nil { return false, err @@ -203,7 +203,7 @@ func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) { } func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) { - rlimits, err := p.fillFromLimitsWithContext() + rlimits, err := p.fillFromLimitsWithContext(ctx) if !gatherUsed || err != nil { return rlimits, err } @@ -258,7 +258,7 @@ func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ( } func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) { - return p.fillFromIOWithContext() + return p.fillFromIOWithContext(ctx) } func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) { @@ -284,7 +284,7 @@ func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) { ret := make(map[int32]*cpu.TimesStat) - taskPath := common.HostProc(strconv.Itoa(int(p.Pid)), "task") + taskPath := common.HostProcWithContext(ctx, strconv.Itoa(int(p.Pid)), "task") tids, err := readPidsFromDir(taskPath) if err != nil { @@ -315,7 +315,7 @@ func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) { } func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) { - meminfo, _, err := p.fillFromStatmWithContext() + meminfo, _, err := p.fillFromStatmWithContext(ctx) if err != nil { return nil, err } @@ -323,7 +323,7 @@ func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, e } func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) { - _, memInfoEx, err := p.fillFromStatmWithContext() + _, memInfoEx, err := p.fillFromStatmWithContext(ctx) if err != nil { return nil, err } @@ -381,12 +381,12 @@ func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) { pid := p.Pid var ret []MemoryMapsStat - smapsPath := common.HostProc(strconv.Itoa(int(pid)), "smaps") + smapsPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "smaps") if grouped { ret = make([]MemoryMapsStat, 1) // If smaps_rollup exists (require kernel >= 4.15), then we will use it // for pre-summed memory information for a process. - smapsRollupPath := common.HostProc(strconv.Itoa(int(pid)), "smaps_rollup") + smapsRollupPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "smaps_rollup") if _, err := os.Stat(smapsRollupPath); !os.IsNotExist(err) { smapsPath = smapsRollupPath } @@ -482,7 +482,7 @@ func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]M } func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) { - environPath := common.HostProc(strconv.Itoa(int(p.Pid)), "environ") + environPath := common.HostProcWithContext(ctx, strconv.Itoa(int(p.Pid)), "environ") environContent, err := ioutil.ReadFile(environPath) if err != nil { @@ -508,9 +508,9 @@ func limitToUint(val string) (uint64, error) { } // Get num_fds from /proc/(pid)/limits -func (p *Process) fillFromLimitsWithContext() ([]RlimitStat, error) { +func (p *Process) fillFromLimitsWithContext(ctx context.Context) ([]RlimitStat, error) { pid := p.Pid - limitsFile := common.HostProc(strconv.Itoa(int(pid)), "limits") + limitsFile := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "limits") d, err := os.Open(limitsFile) if err != nil { return nil, err @@ -603,7 +603,7 @@ func (p *Process) fillFromLimitsWithContext() ([]RlimitStat, error) { // Get list of /proc/(pid)/fd files func (p *Process) fillFromfdListWithContext(ctx context.Context) (string, []string, error) { pid := p.Pid - statPath := common.HostProc(strconv.Itoa(int(pid)), "fd") + statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "fd") d, err := os.Open(statPath) if err != nil { return statPath, []string{}, err @@ -643,9 +643,9 @@ func (p *Process) fillFromfdWithContext(ctx context.Context) (int32, []*OpenFile } // Get cwd from /proc/(pid)/cwd -func (p *Process) fillFromCwdWithContext() (string, error) { +func (p *Process) fillFromCwdWithContext(ctx context.Context) (string, error) { pid := p.Pid - cwdPath := common.HostProc(strconv.Itoa(int(pid)), "cwd") + cwdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cwd") cwd, err := os.Readlink(cwdPath) if err != nil { return "", err @@ -654,9 +654,9 @@ func (p *Process) fillFromCwdWithContext() (string, error) { } // Get exe from /proc/(pid)/exe -func (p *Process) fillFromExeWithContext() (string, error) { +func (p *Process) fillFromExeWithContext(ctx context.Context) (string, error) { pid := p.Pid - exePath := common.HostProc(strconv.Itoa(int(pid)), "exe") + exePath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "exe") exe, err := os.Readlink(exePath) if err != nil { return "", err @@ -667,7 +667,7 @@ func (p *Process) fillFromExeWithContext() (string, error) { // Get cmdline from /proc/(pid)/cmdline func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) { pid := p.Pid - cmdPath := common.HostProc(strconv.Itoa(int(pid)), "cmdline") + cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") cmdline, err := ioutil.ReadFile(cmdPath) if err != nil { return "", err @@ -681,7 +681,7 @@ func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) { pid := p.Pid - cmdPath := common.HostProc(strconv.Itoa(int(pid)), "cmdline") + cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") cmdline, err := ioutil.ReadFile(cmdPath) if err != nil { return nil, err @@ -702,9 +702,9 @@ func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string } // Get IO status from /proc/(pid)/io -func (p *Process) fillFromIOWithContext() (*IOCountersStat, error) { +func (p *Process) fillFromIOWithContext(ctx context.Context) (*IOCountersStat, error) { pid := p.Pid - ioPath := common.HostProc(strconv.Itoa(int(pid)), "io") + ioPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "io") ioline, err := ioutil.ReadFile(ioPath) if err != nil { return nil, err @@ -738,9 +738,9 @@ func (p *Process) fillFromIOWithContext() (*IOCountersStat, error) { } // Get memory info from /proc/(pid)/statm -func (p *Process) fillFromStatmWithContext() (*MemoryInfoStat, *MemoryInfoExStat, error) { +func (p *Process) fillFromStatmWithContext(ctx context.Context) (*MemoryInfoStat, *MemoryInfoExStat, error) { pid := p.Pid - memPath := common.HostProc(strconv.Itoa(int(pid)), "statm") + memPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "statm") contents, err := ioutil.ReadFile(memPath) if err != nil { return nil, nil, err @@ -791,7 +791,7 @@ func (p *Process) fillFromStatmWithContext() (*MemoryInfoStat, *MemoryInfoExStat // Get name from /proc/(pid)/comm or /proc/(pid)/status func (p *Process) fillNameWithContext(ctx context.Context) error { - err := p.fillFromCommWithContext() + err := p.fillFromCommWithContext(ctx) if err == nil && p.name != "" && len(p.name) < 15 { return nil } @@ -799,9 +799,9 @@ func (p *Process) fillNameWithContext(ctx context.Context) error { } // Get name from /proc/(pid)/comm -func (p *Process) fillFromCommWithContext() error { +func (p *Process) fillFromCommWithContext(ctx context.Context) error { pid := p.Pid - statPath := common.HostProc(strconv.Itoa(int(pid)), "comm") + statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "comm") contents, err := ioutil.ReadFile(statPath) if err != nil { return err @@ -818,7 +818,7 @@ func (p *Process) fillFromStatus() error { func (p *Process) fillFromStatusWithContext(ctx context.Context) error { pid := p.Pid - statPath := common.HostProc(strconv.Itoa(int(pid)), "status") + statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "status") contents, err := ioutil.ReadFile(statPath) if err != nil { return err @@ -1023,9 +1023,9 @@ func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (ui var statPath string if tid == -1 { - statPath = common.HostProc(strconv.Itoa(int(pid)), "stat") + statPath = common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "stat") } else { - statPath = common.HostProc(strconv.Itoa(int(pid)), "task", strconv.Itoa(int(tid)), "stat") + statPath = common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "task", strconv.Itoa(int(tid)), "stat") } contents, err := ioutil.ReadFile(statPath) @@ -1129,7 +1129,7 @@ func (p *Process) fillFromStatWithContext(ctx context.Context) (uint64, int32, * } func pidsWithContext(ctx context.Context) ([]int32, error) { - return readPidsFromDir(common.HostProc()) + return readPidsFromDir(common.HostProcWithContext(ctx)) } func ProcessesWithContext(ctx context.Context) ([]*Process, error) { diff --git a/process/process_linux_test.go b/process/process_linux_test.go index 76dee4437..e8c2e8350 100644 --- a/process/process_linux_test.go +++ b/process/process_linux_test.go @@ -4,6 +4,7 @@ package process import ( + "context" "fmt" "io/ioutil" "os" @@ -107,7 +108,7 @@ func Test_fillFromCommWithContext(t *testing.T) { continue } p, _ := NewProcess(int32(pid)) - if err := p.fillFromCommWithContext(); err != nil { + if err := p.fillFromCommWithContext(context.Background()); err != nil { t.Error(err) } } @@ -139,7 +140,7 @@ func Benchmark_fillFromCommWithContext(b *testing.B) { pid := 1060 p, _ := NewProcess(int32(pid)) for i := 0; i < b.N; i++ { - p.fillFromCommWithContext() + p.fillFromCommWithContext(context.Background()) } } diff --git a/process/process_posix.go b/process/process_posix.go index 7bd9b0560..a01f9ecfc 100644 --- a/process/process_posix.go +++ b/process/process_posix.go @@ -109,8 +109,8 @@ func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) { return false, err } - if isMount(common.HostProc()) { // if //proc exists and is mounted, check if //proc/ folder exists - _, err := os.Stat(common.HostProc(strconv.Itoa(int(pid)))) + if isMount(common.HostProcWithContext(ctx)) { // if //proc exists and is mounted, check if //proc/ folder exists + _, err := os.Stat(common.HostProcWithContext(ctx, strconv.Itoa(int(pid)))) if os.IsNotExist(err) { return false, nil } diff --git a/process/process_solaris.go b/process/process_solaris.go index 4f10a67bc..ad1c3cfc1 100644 --- a/process/process_solaris.go +++ b/process/process_solaris.go @@ -30,7 +30,7 @@ type MemoryMapsStat struct { type MemoryInfoExStat struct{} func pidsWithContext(ctx context.Context) ([]int32, error) { - return readPidsFromDir(common.HostProc()) + return readPidsFromDir(common.HostProcWithContext(ctx)) } func ProcessesWithContext(ctx context.Context) ([]*Process, error) { @@ -199,7 +199,7 @@ func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) { func (p *Process) fillFromfdListWithContext(ctx context.Context) (string, []string, error) { pid := p.Pid - statPath := common.HostProc(strconv.Itoa(int(pid)), "fd") + statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "fd") d, err := os.Open(statPath) if err != nil { return statPath, []string{}, err @@ -211,7 +211,7 @@ func (p *Process) fillFromfdListWithContext(ctx context.Context) (string, []stri func (p *Process) fillFromPathCwdWithContext(ctx context.Context) (string, error) { pid := p.Pid - cwdPath := common.HostProc(strconv.Itoa(int(pid)), "path", "cwd") + cwdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "path", "cwd") cwd, err := os.Readlink(cwdPath) if err != nil { return "", err @@ -221,7 +221,7 @@ func (p *Process) fillFromPathCwdWithContext(ctx context.Context) (string, error func (p *Process) fillFromPathAOutWithContext(ctx context.Context) (string, error) { pid := p.Pid - cwdPath := common.HostProc(strconv.Itoa(int(pid)), "path", "a.out") + cwdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "path", "a.out") exe, err := os.Readlink(cwdPath) if err != nil { return "", err @@ -231,7 +231,7 @@ func (p *Process) fillFromPathAOutWithContext(ctx context.Context) (string, erro func (p *Process) fillFromExecnameWithContext(ctx context.Context) (string, error) { pid := p.Pid - execNamePath := common.HostProc(strconv.Itoa(int(pid)), "execname") + execNamePath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "execname") exe, err := ioutil.ReadFile(execNamePath) if err != nil { return "", err @@ -241,7 +241,7 @@ func (p *Process) fillFromExecnameWithContext(ctx context.Context) (string, erro func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) { pid := p.Pid - cmdPath := common.HostProc(strconv.Itoa(int(pid)), "cmdline") + cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") cmdline, err := ioutil.ReadFile(cmdPath) if err != nil { return "", err @@ -258,7 +258,7 @@ func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) { pid := p.Pid - cmdPath := common.HostProc(strconv.Itoa(int(pid)), "cmdline") + cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") cmdline, err := ioutil.ReadFile(cmdPath) if err != nil { return nil, err