Skip to content

Commit

Permalink
Fix ps bug when running parser with invalid input
Browse files Browse the repository at this point in the history
  • Loading branch information
qba73 committed Jun 29, 2024
1 parent 4993e01 commit d97d711
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 55 deletions.
55 changes: 11 additions & 44 deletions stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (
)

type Stats struct {
Memory Memory `json:"memory"`
DiskSpace string `json:"disk_space"`
Uptime string `json:"uptime"`
Processes []Process `json:"processes"`
Memory Memory `json:"memory"`
DiskSpace DiskSpace `json:"disk_space"`
Uptime Uptime `json:"uptime"`
Processes []ProcessInfo `json:"processes"`
}

type Memory struct {
Expand Down Expand Up @@ -85,11 +85,14 @@ type ProcessInfo struct {
Command string
}

// Format: USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
// Format: USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
var psRE = regexp.MustCompile(`^(\w+) +(\d+) +(\d+\.\d+) +(\d+\.\d+) +(\d+) +(\d+) +(.) +(\w+) +([\d:]+) +([\d:]+) +(.+)$`)

func ParsePS(s string) ([]ProcessInfo, error) {
lines := strings.Split(s, "\n")
if len(lines) < 2 {
return nil, fmt.Errorf("invalid input line: %s", s)
}
list := make([]ProcessInfo, 0, len(lines)-1)
const (
USER = iota + 1
Expand All @@ -106,10 +109,9 @@ func ParsePS(s string) ([]ProcessInfo, error) {
)
for _, line := range lines[1 : len(lines)-1] {
matches := psRE.FindStringSubmatch(line)
// if len(matches) != 12 {
// fmt.Printf("%#v)\n", matches)
// return nil, fmt.Errorf("parsing %q", line)
// }
if len(matches) != 12 {
return nil, fmt.Errorf("parsing %q", line)
}
pid, err := strconv.ParseUint(matches[PID], 10, 64)
if err != nil {
return nil, err
Expand Down Expand Up @@ -236,38 +238,3 @@ func ParseUptime(s string) (Uptime, error) {
CPUload15min: load15min,
}, nil
}

type Process struct {
User string `json:"user"`
PID string `json:"pid"`
CPU string `json:"cpu"`
Memory string `json:"memory"`
VSZ string `json:"vsz"`
RSS string `json:"rss"`
TTY string `json:"tty"`
Stat string `json:"stat"`
Start string `json:"start"`
Time string `json:"time"`
Command string `json:"command"`
}

// func ParseProcess(s string) (_ Process, err error) {
// defer func() {
// if err != nil {
// err = fmt.Errorf("parsing `ps -u` command output: %w", err)
// }
// }()

// var (
// user, pid, cpu, mem string
// )

// line := strings.TrimSpace(s)
// chunks := strings.Split(line, "")
// if len(chunks) != 11 {
// return Process{}, err
// }

// return Process{}, nil

// }
22 changes: 11 additions & 11 deletions stats_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

func TestRenderMemoryStats(t *testing.T) {
t.Parallel()

ts := newTestServer("/stats", []byte(statResponse), t)
defer ts.Close()

Expand All @@ -22,7 +21,7 @@ func TestRenderMemoryStats(t *testing.T) {

func TestParseMemoryUsage_ParsesCommandOutputOnValidInput(t *testing.T) {
t.Parallel()

freeCmdOutput := "total used free shared buff/cache available\nMem: 1024 43 816 0 164 980\nSwap: 0 0 0"
got, err := mikrus.ParseMemoryUsage(freeCmdOutput)
if err != nil {
t.Fatal(err)
Expand All @@ -47,7 +46,7 @@ func TestParseMemoryUsage_ParsesCommandOutputOnValidInput(t *testing.T) {

func TestParseDiskSpace_ParsesCommandOutputOnValidInput(t *testing.T) {
t.Parallel()

dfCmdOutput := "Filesystem Size Used Avail Use% Mounted on\n/dev/mapper/pve-vm--230--disk--0 9.8G 2.7G 6.7G 29% /\nudev 63G 0 63G 0% /dev/net"
got, err := mikrus.ParseDiskSpace(dfCmdOutput)
if err != nil {
t.Fatal(err)
Expand All @@ -65,7 +64,7 @@ func TestParseDiskSpace_ParsesCommandOutputOnValidInput(t *testing.T) {
}
}

func TestParseUptime_ParsesUtimeCommandOutputOnValidInput(t *testing.T) {
func TestParseUptime_ParsesUptimeCommandOutput(t *testing.T) {
t.Parallel()
uptimeCmdOutput := "16:32:02 up 6 days, 8:33, 0 users, load average: 0.10, 1.00, 0.50"
wantUptime, err := time.ParseDuration("152h33m0s")
Expand Down Expand Up @@ -96,7 +95,7 @@ func TestParseUptime_ErrorsForInvalidInput(t *testing.T) {
}
}

func TestParsePS_ReturnsCorrectResult(t *testing.T) {
func TestParsePS_ParsesPSCommandOutput(t *testing.T) {
t.Parallel()
psCmdOutput := "USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND\nroot 21605 0.0 0.3 9504 3368 ? S 16:32 0:00 bash -c cat | sh\nroot 21607 0.0 0.0 2608 596 ? S 16:32 0:00 \\_ sh\n"
want := []mikrus.ProcessInfo{
Expand Down Expand Up @@ -136,12 +135,13 @@ func TestParsePS_ReturnsCorrectResult(t *testing.T) {
}
}

var (
freeCmdOutput string = "total used free shared buff/cache available\nMem: 1024 43 816 0 164 980\nSwap: 0 0 0"
dfCmdOutput string = "Filesystem Size Used Avail Use% Mounted on\n/dev/mapper/pve-vm--230--disk--0 9.8G 2.7G 6.7G 29% /\nudev 63G 0 63G 0% /dev/net"
uptimeCmdOutput string = "16:32:02 up 6 days, 8:33, 0 users, load average: 0.00, 0.00, 0.00\nsh: 1: echo"
psCmdOutput string = ": not found\nUSER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND\nroot 21605 0.0 0.3 9504 3368 ? S 16:32 0:00 bash -c cat | sh\nroot 21607 0.0 0.0 2608 596 ? S 16:32 0:00 \\_ sh\nroot 21612 0.0 0.3 11420 3264 ? R 16:32 0:00 \\_ ps auxf\nroot 1 0.0 1.0 169412 10748 ? Ss Jun05 0:04 /sbin/init\nroot 48 0.0 6.0 141148 63436 ? Ss Jun05 0:20 /lib/systemd/systemd-journald\nsystemd+ 73 0.0 0.7 18376 7616 ? Ss Jun05 0:00 /lib/systemd/systemd-networkd\nsystemd+ 89 0.0 1.1 23924 12128 ? Ss Jun05 0:14 /lib/systemd/systemd-resolved\nroot 103 0.0 0.6 238088 7264 ? Ssl Jun05 0:06 /usr/lib/accountsservice/accounts-daemon\nroot 104 0.0 0.2 9344 2796 ? Ss Jun05 0:00 /usr/sbin/cron -f\nmessage+ 105 0.0 0.3 7404 4100 ? Ss Jun05 0:00 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only\nroot 108 0.0 1.7 31804 18404 ? Ss Jun05 0:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers\nsyslog 110 0.0 0.4 154708 4248 ? Ssl Jun05 0:01 /usr/sbin/rsyslogd -n -iNONE\nroot 113 0.0 0.5 16440 6124 ? Ss Jun05 0:00 /lib/systemd/systemd-logind\nroot 122 0.0 0.2 8132 2144 console Ss+ Jun05 0:00 /sbin/agetty -o -p -- \\u --noclear --keep-baud console 115200,38400,9600 linux\nroot 123 0.0 0.2 8132 2248 pts/0 Ss+ Jun05 0:00 /sbin/agetty -o -p -- \\u --noclear --keep-baud tty1 115200,38400,9600 linux\nroot 124 0.0 0.2 8132 2132 pts/1 Ss+ Jun05 0:00 /sbin/agetty -o -p -- \\u --noclear --keep-baud tty2 115200,38400,9600 linux\nroot 126 0.0 0.6 12172 7124 ? Ss Jun05 0:03 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"
)
func TestParsePS_ErrorsForInvalidInput(t *testing.T) {
t.Parallel()
_, err := mikrus.ParsePS("bogus")
if err == nil {
t.Fatal("want error for invalid input, got nil")
}
}

var statResponse = `{
"free": "total used free shared buff/cache available\nMem: 1024 43 816 0 164 980\nSwap: 0 0 0",
Expand Down

0 comments on commit d97d711

Please sign in to comment.