Repository: prometheus/procfs
Pull request #460 (2022-07-14 16:51:24)

Add sysctl


Patch:
diff --git a/internal/util/sysreadfile.go b/internal/util/sysreadfile.go
index bd6ea1e..1ab875c 100644
--- a/internal/util/sysreadfile.go
+++ b/internal/util/sysreadfile.go
@@ -11,8 +11,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//go:build linux && !appengine
-// +build linux,!appengine
+//go:build (linux || darwin) && !appengine
+// +build linux darwin
+// +build !appengine
 
 package util
 
diff --git a/internal/util/sysreadfile_compat.go b/internal/util/sysreadfile_compat.go
index 8702ab3..1d86f5e 100644
--- a/internal/util/sysreadfile_compat.go
+++ b/internal/util/sysreadfile_compat.go
@@ -11,8 +11,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//go:build (linux && appengine) || !linux
-// +build linux,appengine !linux
+//go:build (linux && appengine) || (!linux && !darwin)
+// +build linux,appengine !linux,!darwin
 
 package util
 
diff --git a/proc_sys.go b/proc_sys.go
new file mode 100644
index 0000000..d46533e
--- /dev/null
+++ b/proc_sys.go
@@ -0,0 +1,51 @@
+// Copyright 2022 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/prometheus/procfs/internal/util"
+)
+
+func sysctlToPath(sysctl string) string {
+	return strings.Replace(sysctl, ".", "/", -1)
+}
+
+func (fs FS) SysctlStrings(sysctl string) ([]string, error) {
+	value, err := util.SysReadFile(fs.proc.Path("sys", sysctlToPath(sysctl)))
+	if err != nil {
+		return nil, err
+	}
+	return strings.Fields(value), nil
+
+}
+
+func (fs FS) SysctlInts(sysctl string) ([]int, error) {
+	fields, err := fs.SysctlStrings(sysctl)
+	if err != nil {
+		return nil, err
+	}
+
+	values := make([]int, len(fields))
+	for i, f := range fields {
+		vp := util.NewValueParser(f)
+		values[i] = vp.Int()
+		if err := vp.Err(); err != nil {
+			return nil, fmt.Errorf("field %d in sysctl %s is not a valid int: %w", i, sysctl, err)
+		}
+	}
+	return values, nil
+}


Test patch:
diff --git a/proc_sys_test.go b/proc_sys_test.go
new file mode 100644
index 0000000..2f8b867
--- /dev/null
+++ b/proc_sys_test.go
@@ -0,0 +1,84 @@
+// Copyright 2022 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+)
+
+func TestSysctlInts(t *testing.T) {
+	fs := getProcFixtures(t)
+
+	for _, tc := range []struct {
+		sysctl string
+		want   []int
+	}{
+		{"kernel.random.entropy_avail", []int{3943}},
+		{"vm.lowmem_reserve_ratio", []int{256, 256, 32, 0, 0}},
+	} {
+		t.Run(tc.sysctl, func(t *testing.T) {
+			got, err := fs.SysctlInts(tc.sysctl)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if diff := cmp.Diff(tc.want, got); diff != "" {
+				t.Fatalf("unexpected syscall value(-want +got):\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestSysctlStrings(t *testing.T) {
+	fs := getProcFixtures(t)
+
+	for _, tc := range []struct {
+		sysctl string
+		want   []string
+	}{
+		{"kernel.seccomp.actions_avail", []string{"kill_process", "kill_thread", "trap", "errno", "trace", "log", "allow"}},
+	} {
+		t.Run(tc.sysctl, func(t *testing.T) {
+			got, err := fs.SysctlStrings(tc.sysctl)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if diff := cmp.Diff(tc.want, got); diff != "" {
+				t.Fatalf("unexpected syscall value(-want +got):\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestSysctlIntsError(t *testing.T) {
+	fs := getProcFixtures(t)
+
+	for _, tc := range []struct {
+		sysctl string
+		want   string
+	}{
+		{"kernel.seccomp.actions_avail", "field 0 in sysctl kernel.seccomp.actions_avail is not a valid int: strconv.ParseInt: parsing \"kill_process\": invalid syntax"},
+	} {
+		t.Run(tc.sysctl, func(t *testing.T) {
+			_, err := fs.SysctlInts(tc.sysctl)
+			if err == nil {
+				t.Fatal("expected error")
+			}
+			if diff := cmp.Diff(tc.want, err.Error()); diff != "" {
+				t.Fatalf("unexpected syscall value(-want +got):\n%s", diff)
+			}
+		})
+	}
+}
diff --git a/testdata/fixtures.ttar b/testdata/fixtures.ttar
index bd25048..40b6307 100644
--- a/testdata/fixtures.ttar
+++ b/testdata/fixtures.ttar
@@ -2873,6 +2873,14 @@ Lines: 1
 3072
 Mode: 644
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/sys/kernel/seccomp
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/sys/kernel/seccomp/actions_avail
+Lines: 1
+kill_process kill_thread trap errno trace log allow
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Directory: fixtures/proc/sys/vm
 Mode: 775
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -