mirror of
https://github.com/kubernetes/node-problem-detector.git
synced 2026-02-14 18:09:57 +00:00
support custom /proc path
This commit is contained in:
@@ -46,13 +46,17 @@ type cpuCollector struct {
|
||||
mSystemInterruptsTotal *metrics.Int64Metric
|
||||
mSystemCPUStat *metrics.Float64Metric // per-cpu time from /proc/stats
|
||||
|
||||
config *ssmtypes.CPUStatsConfig
|
||||
config *ssmtypes.CPUStatsConfig
|
||||
procPath string
|
||||
|
||||
lastUsageTime map[string]float64
|
||||
}
|
||||
|
||||
func NewCPUCollectorOrDie(cpuConfig *ssmtypes.CPUStatsConfig) *cpuCollector {
|
||||
cc := cpuCollector{config: cpuConfig}
|
||||
func NewCPUCollectorOrDie(cpuConfig *ssmtypes.CPUStatsConfig, procPath string) *cpuCollector {
|
||||
cc := cpuCollector{
|
||||
config: cpuConfig,
|
||||
procPath: procPath,
|
||||
}
|
||||
|
||||
var err error
|
||||
cc.mRunnableTaskCount, err = metrics.NewFloat64Metric(
|
||||
|
||||
@@ -52,7 +52,6 @@ func (cc *cpuCollector) recordLoad() {
|
||||
}
|
||||
|
||||
func (cc *cpuCollector) recordSystemStats() {
|
||||
|
||||
// don't collect the load metrics if the configs are not present.
|
||||
if cc.mSystemCPUStat == nil && cc.mSystemInterruptsTotal == nil &&
|
||||
cc.mSystemProcessesTotal == nil && cc.mSystemProcsBlocked == nil &&
|
||||
@@ -60,7 +59,7 @@ func (cc *cpuCollector) recordSystemStats() {
|
||||
return
|
||||
}
|
||||
|
||||
fs, err := procfs.NewFS("/proc")
|
||||
fs, err := procfs.NewFS(cc.procPath)
|
||||
stats, err := fs.Stat()
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to retrieve cpu/process stats: %v", err)
|
||||
|
||||
@@ -67,6 +67,6 @@ func TestCpuCollector(t *testing.T) {
|
||||
if err := json.Unmarshal([]byte(fakeCPUConfig), cfg); err != nil {
|
||||
t.Fatalf("cannot load cpu config: %s", err)
|
||||
}
|
||||
mc := NewCPUCollectorOrDie(cfg)
|
||||
mc := NewCPUCollectorOrDie(cfg, "/proc")
|
||||
mc.collect()
|
||||
}
|
||||
|
||||
@@ -28,12 +28,14 @@ import (
|
||||
|
||||
type netCollector struct {
|
||||
config *ssmtypes.NetStatsConfig
|
||||
procPath string
|
||||
recorder *ifaceStatRecorder
|
||||
}
|
||||
|
||||
func NewNetCollectorOrDie(netConfig *ssmtypes.NetStatsConfig) *netCollector {
|
||||
func NewNetCollectorOrDie(netConfig *ssmtypes.NetStatsConfig, procPath string) *netCollector {
|
||||
nc := netCollector{
|
||||
config: netConfig,
|
||||
procPath: procPath,
|
||||
recorder: newIfaceStatRecorder(),
|
||||
}
|
||||
|
||||
@@ -207,7 +209,7 @@ func (nc *netCollector) mustRegisterMetric(metricID metrics.MetricID, descriptio
|
||||
}
|
||||
|
||||
func (nc *netCollector) recordNetDev() {
|
||||
fs, err := procfs.NewFS("/proc")
|
||||
fs, err := procfs.NewFS(nc.procPath)
|
||||
stats, err := fs.NetDev()
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to retrieve net dev stat: %v", err)
|
||||
|
||||
@@ -16,6 +16,7 @@ package systemstatsmonitor
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -27,11 +28,15 @@ import (
|
||||
|
||||
type osFeatureCollector struct {
|
||||
config *ssmtypes.OSFeatureStatsConfig
|
||||
procPath string
|
||||
osFeature *metrics.Int64Metric
|
||||
}
|
||||
|
||||
func NewOsFeatureCollectorOrDie(osFeatureConfig *ssmtypes.OSFeatureStatsConfig) *osFeatureCollector {
|
||||
oc := osFeatureCollector{config: osFeatureConfig}
|
||||
func NewOsFeatureCollectorOrDie(osFeatureConfig *ssmtypes.OSFeatureStatsConfig, procPath string) *osFeatureCollector {
|
||||
oc := osFeatureCollector{
|
||||
config: osFeatureConfig,
|
||||
procPath: procPath,
|
||||
}
|
||||
var err error
|
||||
// Use metrics.Last aggregation method to ensure the metric is a guage metric.
|
||||
if osFeatureConfig.MetricsConfigs["system/os_feature"].DisplayName != "" {
|
||||
@@ -145,12 +150,12 @@ func (ofc *osFeatureCollector) collect() {
|
||||
if ofc == nil || ofc.osFeature == nil {
|
||||
return
|
||||
}
|
||||
cmdlineArgs, err := system.CmdlineArgs()
|
||||
cmdlineArgs, err := system.CmdlineArgs(filepath.Join(ofc.procPath, "/cmdline"))
|
||||
if err != nil {
|
||||
glog.Fatalf("Error retrieving cmdline args: %v", err)
|
||||
}
|
||||
ofc.recordFeaturesFromCmdline(cmdlineArgs)
|
||||
modules, err := system.Modules()
|
||||
modules, err := system.Modules(filepath.Join(ofc.procPath, "/modules"))
|
||||
if err != nil {
|
||||
glog.Fatalf("Error retrieving kernel modules: %v", err)
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ func NewSystemStatsMonitorOrDie(configPath string) types.Monitor {
|
||||
}
|
||||
|
||||
if len(ssm.config.CPUConfig.MetricsConfigs) > 0 {
|
||||
ssm.cpuCollector = NewCPUCollectorOrDie(&ssm.config.CPUConfig)
|
||||
ssm.cpuCollector = NewCPUCollectorOrDie(&ssm.config.CPUConfig, ssm.config.ProcPath)
|
||||
}
|
||||
if len(ssm.config.DiskConfig.MetricsConfigs) > 0 {
|
||||
ssm.diskCollector = NewDiskCollectorOrDie(&ssm.config.DiskConfig)
|
||||
@@ -96,10 +96,10 @@ func NewSystemStatsMonitorOrDie(configPath string) types.Monitor {
|
||||
ssm.config.OsFeatureConfig.KnownModulesConfigPath = filepath.Join(filepath.Dir(configPath),
|
||||
ssm.config.OsFeatureConfig.KnownModulesConfigPath)
|
||||
}
|
||||
ssm.osFeatureCollector = NewOsFeatureCollectorOrDie(&ssm.config.OsFeatureConfig)
|
||||
ssm.osFeatureCollector = NewOsFeatureCollectorOrDie(&ssm.config.OsFeatureConfig, ssm.config.ProcPath)
|
||||
}
|
||||
if len(ssm.config.NetConfig.MetricsConfigs) > 0 {
|
||||
ssm.netCollector = NewNetCollectorOrDie(&ssm.config.NetConfig)
|
||||
ssm.netCollector = NewNetCollectorOrDie(&ssm.config.NetConfig, ssm.config.ProcPath)
|
||||
}
|
||||
return &ssm
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -25,6 +26,7 @@ var (
|
||||
defaultInvokeIntervalString = (60 * time.Second).String()
|
||||
defaultlsblkTimeoutString = (5 * time.Second).String()
|
||||
defaultKnownModulesConfigPath = "guestosconfig/known-modules.json"
|
||||
defaultProcPath = "/proc"
|
||||
)
|
||||
|
||||
type MetricConfig struct {
|
||||
@@ -69,6 +71,7 @@ type SystemStatsConfig struct {
|
||||
NetConfig NetStatsConfig `json:"net"`
|
||||
InvokeIntervalString string `json:"invokeInterval"`
|
||||
InvokeInterval time.Duration `json:"-"`
|
||||
ProcPath string `json:"procPath"`
|
||||
}
|
||||
|
||||
// ApplyConfiguration applies default configurations.
|
||||
@@ -76,6 +79,9 @@ func (ssc *SystemStatsConfig) ApplyConfiguration() error {
|
||||
if ssc.InvokeIntervalString == "" {
|
||||
ssc.InvokeIntervalString = defaultInvokeIntervalString
|
||||
}
|
||||
if ssc.ProcPath == "" {
|
||||
ssc.ProcPath = defaultProcPath
|
||||
}
|
||||
if ssc.DiskConfig.LsblkTimeoutString == "" {
|
||||
ssc.DiskConfig.LsblkTimeoutString = defaultlsblkTimeoutString
|
||||
}
|
||||
@@ -101,6 +107,9 @@ func (ssc *SystemStatsConfig) Validate() error {
|
||||
if ssc.InvokeInterval <= time.Duration(0) {
|
||||
return fmt.Errorf("InvokeInterval %v must be above 0s", ssc.InvokeInterval)
|
||||
}
|
||||
if _, err := os.Stat(ssc.ProcPath); err != nil {
|
||||
return fmt.Errorf("ProcPath %v check failed: %s", ssc.ProcPath, err)
|
||||
}
|
||||
if ssc.DiskConfig.LsblkTimeout <= time.Duration(0) {
|
||||
return fmt.Errorf("LsblkTimeout %v must be above 0s", ssc.DiskConfig.LsblkTimeout)
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ func TestApplyConfiguration(t *testing.T) {
|
||||
},
|
||||
InvokeIntervalString: "60s",
|
||||
InvokeInterval: 60 * time.Second,
|
||||
ProcPath: defaultProcPath,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -66,6 +67,7 @@ func TestApplyConfiguration(t *testing.T) {
|
||||
},
|
||||
InvokeIntervalString: "1m0s",
|
||||
InvokeInterval: 60 * time.Second,
|
||||
ProcPath: defaultProcPath,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -19,8 +19,6 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var cmdlineFilePath = "/proc/cmdline"
|
||||
|
||||
type CmdlineArg struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
@@ -52,7 +50,7 @@ func splitAfterSpace(inputChar rune) bool {
|
||||
}
|
||||
|
||||
// CmdlineArgs returns all the kernel cmdline. It is read from cat /proc/cmdline.
|
||||
func CmdlineArgs() ([]CmdlineArg, error) {
|
||||
func CmdlineArgs(cmdlineFilePath string) ([]CmdlineArg, error) {
|
||||
lines, err := ReadFileIntoLines(cmdlineFilePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading the file %s, %v", cmdlineFilePath, err)
|
||||
|
||||
@@ -69,15 +69,9 @@ func TestCmdlineStats(t *testing.T) {
|
||||
}
|
||||
for _, test := range testcases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
originalCmdlineFilePath := cmdlineFilePath
|
||||
defer func() {
|
||||
cmdlineFilePath = originalCmdlineFilePath
|
||||
}()
|
||||
|
||||
cmdlineFilePath = test.fakeCmdlineFilePath
|
||||
cmdlineArgs, err := CmdlineArgs()
|
||||
cmdlineArgs, err := CmdlineArgs(test.fakeCmdlineFilePath)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error retrieving cmdlineArgs: %v\nCmdlineArgsFilePath: %s\n", err, cmdlineFilePath)
|
||||
t.Errorf("Unexpected error retrieving cmdlineArgs: %v\nCmdlineArgsFilePath: %s\n", err, test.fakeCmdlineFilePath)
|
||||
}
|
||||
for _, expectedCmdlineArg := range test.expectedCmdlineArgs {
|
||||
assert.Contains(t, cmdlineArgs, expectedCmdlineArg, "Failed to find cmdlineArgs: %v\n", expectedCmdlineArg)
|
||||
|
||||
@@ -20,8 +20,6 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var modulesFilePath = "/proc/modules"
|
||||
|
||||
type Module struct {
|
||||
ModuleName string `json:"moduleName"`
|
||||
Instances uint64 `json:"instances"`
|
||||
@@ -37,7 +35,7 @@ func (d Module) String() string {
|
||||
|
||||
// Module returns all the kernel modules and their
|
||||
// usage. It is read from cat /proc/modules.
|
||||
func Modules() ([]Module, error) {
|
||||
func Modules(modulesFilePath string) ([]Module, error) {
|
||||
lines, err := ReadFileIntoLines(modulesFilePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading the contents of %s: %s", modulesFilePath, err)
|
||||
|
||||
@@ -97,15 +97,9 @@ func TestModules(t *testing.T) {
|
||||
}
|
||||
for _, test := range testcases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
originalModuleFilePath := modulesFilePath
|
||||
defer func() {
|
||||
modulesFilePath = originalModuleFilePath
|
||||
}()
|
||||
|
||||
modulesFilePath = test.fakeModuleFilePath
|
||||
modules, err := Modules()
|
||||
modules, err := Modules(test.fakeModuleFilePath)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error retrieving modules: %v\nModulesFilePath: %s\n", err, modulesFilePath)
|
||||
t.Errorf("Unexpected error retrieving modules: %v\nModulesFilePath: %s\n", err, test.fakeModuleFilePath)
|
||||
}
|
||||
assert.Equal(t, modules, test.expectedModules, "unpected modules retrieved: %v, expected: %v", modules, test.expectedModules)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user