-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
67a1c53
commit 2b0bbe7
Showing
13 changed files
with
475 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
launcher/internal/healthmonitoring/nodeproblemdetector/systemstats_config.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Package nodeproblemdetector provides configurations for node-problem-detector.service. | ||
package nodeproblemdetector | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"os" | ||
"time" | ||
) | ||
|
||
var defaultInvokeIntervalString = (60 * time.Second).String() | ||
|
||
type metricConfig struct { | ||
DisplayName string `json:"displayName"` | ||
} | ||
|
||
type memoryStatsConfig struct { | ||
MetricsConfigs map[string]metricConfig `json:"metricsConfigs"` | ||
} | ||
|
||
// SystemStatsConfig contains configurations for `System Stats Monitor`, | ||
// a problem daemon in node-problem-detector that collects pre-defined health-related metrics from different system components. | ||
// For now we only consider collecting memory related metrics. | ||
// View the comprehensive configuration details on https://github.com/kubernetes/node-problem-detector/tree/master/pkg/systemstatsmonitor#detailed-configuration-options | ||
type SystemStatsConfig struct { | ||
MemoryStatsConfig memoryStatsConfig `json:"memory"` | ||
InvokeInterval string `json:"invokeInterval"` | ||
} | ||
|
||
// NewSystemStatsConfig returns a new SystemStatsConfig struct with default configurations. | ||
func NewSystemStatsConfig() SystemStatsConfig { | ||
return SystemStatsConfig{ | ||
MemoryStatsConfig: memoryStatsConfig{MetricsConfigs: map[string]metricConfig{}}, | ||
InvokeInterval: defaultInvokeIntervalString, | ||
} | ||
} | ||
|
||
// EnableMemoryBytesUsed enables "memory/bytes_used" for memory monitoring. | ||
func (ssc *SystemStatsConfig) EnableMemoryBytesUsed() { | ||
ssc.MemoryStatsConfig.MetricsConfigs["memory/bytes_used"] = metricConfig{DisplayName: "memory/bytes_used"} | ||
} | ||
|
||
// WithInvokeInterval overrides the default invokeInterval. | ||
func (ssc *SystemStatsConfig) WithInvokeInterval(interval time.Duration) { | ||
ssc.InvokeInterval = interval.String() | ||
} | ||
|
||
// WriteFile writes systemStatsConfig data to the named file, creating it if necessary. | ||
func (ssc *SystemStatsConfig) WriteFile(path string) error { | ||
bytes, err := json.Marshal(ssc) | ||
if err != nil { | ||
return fmt.Errorf("failed to marshal struct [%v]: %w", ssc, err) | ||
} | ||
return os.WriteFile(path, bytes, 0644) | ||
} |
65 changes: 65 additions & 0 deletions
65
launcher/internal/healthmonitoring/nodeproblemdetector/systemstats_config_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package nodeproblemdetector | ||
|
||
import ( | ||
"bytes" | ||
"io" | ||
"os" | ||
"path" | ||
"testing" | ||
"time" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
) | ||
|
||
func TestEnableMemoryBytesUsed(t *testing.T) { | ||
got := NewSystemStatsConfig() | ||
got.EnableMemoryBytesUsed() | ||
|
||
want := SystemStatsConfig{ | ||
MemoryStatsConfig: memoryStatsConfig{ | ||
MetricsConfigs: map[string]metricConfig{ | ||
"memory/bytes_used": {DisplayName: "memory/bytes_used"}, | ||
}, | ||
}, | ||
InvokeInterval: defaultInvokeIntervalString, | ||
} | ||
if !cmp.Equal(got, want) { | ||
t.Errorf("EnableMemoryBytesUsed() failed, got: %v, want: %v", got, want) | ||
} | ||
} | ||
|
||
func TestWithInvokeInterval(t *testing.T) { | ||
got := SystemStatsConfig{} | ||
got.WithInvokeInterval(2 * time.Second) | ||
|
||
want := SystemStatsConfig{InvokeInterval: (2 * time.Second).String()} | ||
if !cmp.Equal(got, want) { | ||
t.Errorf("WithInvokeInterval() failed, got: %v, want: %v", got, want) | ||
} | ||
} | ||
|
||
func TestWriteFile(t *testing.T) { | ||
tmpDir := t.TempDir() | ||
tmpConfigFile := path.Join(tmpDir, "system-stats-monitor.json") | ||
|
||
config := NewSystemStatsConfig() | ||
config.EnableMemoryBytesUsed() | ||
if err := config.WriteFile(tmpConfigFile); err != nil { | ||
t.Fatalf("WriteFile() failed: %v", err) | ||
} | ||
|
||
file, err := os.OpenFile(tmpConfigFile, os.O_RDONLY, 0) | ||
if err != nil { | ||
t.Fatalf("failed to open file %s: %v", tmpConfigFile, err) | ||
} | ||
|
||
gotBytes, err := io.ReadAll(file) | ||
if err != nil { | ||
t.Fatalf("failed to read from file %s: %v", tmpConfigFile, err) | ||
} | ||
|
||
wantBytes := []byte(`{"memory":{"metricsConfigs":{"memory/bytes_used":{"displayName":"memory/bytes_used"}}},"invokeInterval":"1m0s"}`) | ||
if !bytes.Equal(gotBytes, wantBytes) { | ||
t.Errorf("WriteFile() did not write expected contents, got %s, want %s", gotBytes, wantBytes) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// Package systemctl implements a subset of systemctl operations. | ||
package systemctl | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
|
||
"github.com/coreos/go-systemd/dbus" | ||
) | ||
|
||
// Systemd is an interface to connect to host systemd with selected functions. | ||
type Systemd interface { | ||
Start(string) error | ||
Stop(string) error | ||
Close() | ||
} | ||
|
||
// Systemctl is a wrap around of dbus.Conn and implements the Systemd interface. | ||
type Systemctl struct { | ||
dbus *dbus.Conn | ||
} | ||
|
||
var _ Systemd = (*Systemctl)(nil) | ||
|
||
// New connects to systemd over dbus. | ||
func New() (*Systemctl, error) { | ||
conn, err := dbus.New() | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &Systemctl{dbus: conn}, nil | ||
} | ||
|
||
// Start is the equivalent of `systemctl start $unit`. | ||
func (s *Systemctl) Start(unit string) error { | ||
return runSystemdCmd(s.dbus.StartUnit, "start", unit) | ||
} | ||
|
||
// Stop is the equivalent of `systemctl stop $unit`. | ||
func (s *Systemctl) Stop(unit string) error { | ||
return runSystemdCmd(s.dbus.StopUnit, "stop", unit) | ||
} | ||
|
||
// Close disconnects from dbus. | ||
func (s *Systemctl) Close() { s.dbus.Close() } | ||
|
||
func runSystemdCmd(cmdFunc func(string, string, chan<- string) (int, error), cmd string, unit string) error { | ||
progress := make(chan string, 1) | ||
|
||
// Run systemd command in "replace" mode to start the unit and its dependencies, | ||
// possibly replacing already queued jobs that conflict w∏ith this. | ||
if _, err := cmdFunc(unit, "replace", progress); err != nil { | ||
return fmt.Errorf("failed to run systemctl [%s] for unit [%s]: %v", cmd, unit, err) | ||
} | ||
|
||
if result := <-progress; result != "done" { | ||
return fmt.Errorf("systemctl [%s] result was [%s], want done", cmd, result) | ||
} | ||
|
||
log.Printf("Finished up systemctl [%s] for unit [%s]", cmd, unit) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package systemctl | ||
|
||
import ( | ||
"errors" | ||
"testing" | ||
) | ||
|
||
func TestRunSystmedCmd(t *testing.T) { | ||
doneUnitFunc := func(unit string, mode string, progress chan<- string) (int, error) { | ||
progress <- "done" | ||
return 1, nil | ||
} | ||
failedCallUnitFunc := func(unit string, mode string, progress chan<- string) (int, error) { | ||
return 1, errors.New("something went wrong") | ||
} | ||
failedUnitFunc := func(unit string, mode string, progress chan<- string) (int, error) { | ||
progress <- "failed" | ||
return 1, nil | ||
} | ||
|
||
testCases := []struct { | ||
name string | ||
sytemdCmdFunc func(unit string, flag string, progress chan<- string) (int, error) | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "success", | ||
sytemdCmdFunc: doneUnitFunc, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "failed call", | ||
sytemdCmdFunc: failedCallUnitFunc, | ||
wantErr: true, | ||
}, | ||
{ | ||
name: "failed unit run", | ||
sytemdCmdFunc: failedUnitFunc, | ||
wantErr: true, | ||
}, | ||
} | ||
|
||
for _, tc := range testCases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
if err := runSystemdCmd(tc.sytemdCmdFunc, "test", "test_unit"); (err != nil) != tc.wantErr { | ||
t.Errorf("runSystemdCmd() did not return expected error, got error: %v, but wantErr %v", err, tc.wantErr) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.