Skip to content

Commit

Permalink
chore: go back to sysctl exec
Browse files Browse the repository at this point in the history
  • Loading branch information
JGAntunes committed Nov 7, 2024
1 parent e215789 commit 31172fb
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 60 deletions.
4 changes: 0 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ require (
github.com/hashicorp/go-multierror v1.1.1
github.com/jackc/pgx/v5 v5.7.1
github.com/longhorn/go-iscsi-helper v0.0.0-20210330030558-49a327fb024e
github.com/lorenzosaino/go-sysctl v0.3.1
github.com/manifoldco/promptui v0.9.0
github.com/mattn/go-isatty v0.0.20
github.com/mholt/archiver/v3 v3.5.1
Expand Down Expand Up @@ -129,13 +128,10 @@ require (
go.opentelemetry.io/otel/metric v1.31.0 // indirect
go.opentelemetry.io/otel/trace v1.31.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d // indirect
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
golang.org/x/tools v0.22.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
honnef.co/go/tools v0.3.2 // indirect
k8s.io/component-base v0.31.2 // indirect
k8s.io/kubectl v0.31.1 // indirect
)
Expand Down
7 changes: 0 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -651,8 +651,6 @@ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9
github.com/longhorn/go-iscsi-helper v0.0.0-20210330030558-49a327fb024e h1:hz4quJkaJWDo+xW+G6wTF6d6/95QvJ+o2D0+bB/tJ1U=
github.com/longhorn/go-iscsi-helper v0.0.0-20210330030558-49a327fb024e/go.mod h1:9z/y9glKmWEdV50tjlUPxFwi1goQfIrrsoZbnMyIZbY=
github.com/longhorn/nsfilelock v0.0.0-20200723175406-fa7c83ad0003/go.mod h1:0CLeXlf59Lg6C0kjLSDf47ft73Dh37CwymYRKWwAn04=
github.com/lorenzosaino/go-sysctl v0.3.1 h1:3phX80tdITw2fJjZlwbXQnDWs4S30beNcMbw0cn0HtY=
github.com/lorenzosaino/go-sysctl v0.3.1/go.mod h1:5grcsBRpspKknNS1qzt1eIeRDLrhpKZAtz8Fcuvs1Rc=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
Expand Down Expand Up @@ -990,8 +988,6 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d h1:+W8Qf4iJtMGKkyAygcKohjxTk4JPsL9DpzApJ22m5Ic=
golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
Expand All @@ -1005,7 +1001,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
Expand Down Expand Up @@ -1548,8 +1543,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.3.2 h1:ytYb4rOqyp1TSa2EPvNVwtPQJctSELKaMyLfqNP4+34=
honnef.co/go/tools v0.3.2/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw=
k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0=
k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk=
k8s.io/apiextensions-apiserver v0.31.2 h1:W8EwUb8+WXBLu56ser5IudT2cOho0gAKeTOnywBLxd0=
Expand Down
54 changes: 44 additions & 10 deletions pkg/collect/host_sysctl.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
package collect

import (
"bufio"
"bytes"
"encoding/json"
"os/exec"
"regexp"

"github.com/lorenzosaino/go-sysctl"
"github.com/pkg/errors"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"k8s.io/klog/v2"
)

// Ensure `CollectHostSysctl` implements `HostCollector` interface at compile time.
var _ HostCollector = (*CollectHostSysctl)(nil)

// Path to the kernel virtual files, defaults to /proc/sys
var sysctlVirtualFiles = sysctl.DefaultPath
// Helper var to allow stubbing `exec.Command` for tests
var execCommand = exec.Command

const HostSysctlPath = `host-collectors/system/sysctl.json`

Expand All @@ -31,22 +34,53 @@ func (c *CollectHostSysctl) IsExcluded() (bool, error) {
}

func (c *CollectHostSysctl) Collect(progressChan chan<- interface{}) (map[string][]byte, error) {
client, err := sysctl.NewClient(sysctlVirtualFiles)
klog.V(2).Info("Running sysctl collector")
cmd := execCommand("sysctl", "-a")
out, err := cmd.Output()
if err != nil {
return nil, errors.Wrap(err, "failed to initialize sysctl client")
}

values, err := client.GetAll()
if err != nil {
return nil, errors.Wrap(err, "failed to run sysctl client")
klog.V(2).ErrorS(err, "failed to run sysctl")
if exitErr, ok := err.(*exec.ExitError); ok {
return nil, errors.Wrapf(err, "failed to run sysctl exit-code=%d stderr=%s", exitErr.ExitCode(), exitErr.Stderr)
} else {
return nil, errors.Wrap(err, "failed to run sysctl")
}
}
values := parseSysctlParameters(out)

payload, err := json.Marshal(values)
if err != nil {
klog.V(2).ErrorS(err, "failed to marshal data to json")
return nil, errors.Wrap(err, "failed to marshal data to json")
}

output := NewResult()
output.SaveResult(c.BundlePath, HostSysctlPath, bytes.NewBuffer(payload))
klog.V(2).Info("Finished writing JSON output")
return output, nil
}

// Linux sysctl outputs <key> = <value> where in Darwin you get <key> : <value>
// where <value> can be a string, number or multiple space separated strings
var sysctlLineRegex = regexp.MustCompile(`(\S+)\s*(=|:)\s*(.*)$`)

func parseSysctlParameters(output []byte) map[string]string {
scanner := bufio.NewScanner(bytes.NewReader(output))

result := map[string]string{}
for scanner.Scan() {
l := scanner.Text()
// <1:key> <2:separator> <3:value>
matches := sysctlLineRegex.FindStringSubmatch(l)
// there are no matches for the value and separator, ignore and log
if len(matches) < 3 {
klog.V(2).Infof("skipping sysctl line since we found no matches for it: %s", l)
// key exists but value could be empty, register as an empty string value but log something for reference
} else if len(matches) < 4 {
klog.V(2).Infof("found no value for sysctl line, keeping it with an empty value: %s", l)
result[matches[1]] = ""
} else {
result[matches[1]] = matches[3]
}
}
return result
}
131 changes: 92 additions & 39 deletions pkg/collect/host_sysctl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,71 +2,124 @@ package collect

import (
"encoding/json"
"fmt"
"os"
"os/exec"
"testing"

troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/multitype"
"github.com/stretchr/testify/require"
)

func setKernelVirtualFilesPath(path string) {
sysctlVirtualFiles = path
type execStub struct {
cmd *exec.Cmd
name string
args []string
}

func (s *execStub) testExecCommand(name string, args ...string) *exec.Cmd {
s.name = name
s.args = args
return s.cmd
}

func setExecStub(c *exec.Cmd) {
e := &execStub{
cmd: c,
}
execCommand = e.testExecCommand
}

func TestCollectHostSysctl_Error(t *testing.T) {
req := require.New(t)
tmpDir := t.TempDir()

setKernelVirtualFilesPath(fmt.Sprintf("%s/does/not/exist", tmpDir))
setExecStub(exec.Command("sh", "-c", "exit 1"))

tmpDir := t.TempDir()
c := &CollectHostSysctl{
BundlePath: tmpDir,
}

_, err := c.Collect(nil)
req.ErrorContains(err, "failed to initialize sysctl client")
req.ErrorContains(err, "failed to run sysctl exit-code=1")
}

func TestCollectHostSysctl(t *testing.T) {
req := require.New(t)
expectedOut := map[string]string{
"net.ipv4.conf.all.arp_ignore": "0",
"net.ipv4.conf.all.arp_filter": "1",
"net.ipv4.conf.all.arp_evict_nocarrier": "1",
func TestCollectHostSysctl_(t *testing.T) {
tests := []struct {
name string
cmdOut string
expected map[string]string
}{
{
name: "linux",
cmdOut: `
net.ipv4.conf.all.arp_evict_nocarrier = 1
net.ipv4.conf.all.arp_filter = 0
net.ipv4.conf.all.arp_ignore = 0
`,
expected: map[string]string{
"net.ipv4.conf.all.arp_evict_nocarrier": "1",
"net.ipv4.conf.all.arp_filter": "0",
"net.ipv4.conf.all.arp_ignore": "0",
},
},
{
name: "darwin",
cmdOut: `
kern.prng.pool_31.max_sample_count: 16420665
kern.crypto.sha1: SHA1_VNG_ARM
kern.crypto.sha512: SHA512_VNG_ARM_HW
kern.crypto.aes.ecb.encrypt: AES_ECB_ARM
kern.monotonicclock: 4726514
kern.monotonicclock_usecs: 4726514658233 13321990885027
`,
expected: map[string]string{
"kern.prng.pool_31.max_sample_count": "16420665",
"kern.crypto.sha1": "SHA1_VNG_ARM",
"kern.crypto.sha512": "SHA512_VNG_ARM_HW",
"kern.crypto.aes.ecb.encrypt": "AES_ECB_ARM",
"kern.monotonicclock": "4726514",
"kern.monotonicclock_usecs": "4726514658233 13321990885027",
},
},
{
name: "skip non valid entries and keep empty values",
cmdOut: `
net.ipv4.conf.all.arp_ignore =
kern.prng.pool_31.max_sample_count:
not-valid
net.ipv4.conf.all.arp_filter = 0
`,
expected: map[string]string{
"net.ipv4.conf.all.arp_ignore": "",
"kern.prng.pool_31.max_sample_count": "",
"net.ipv4.conf.all.arp_filter": "0",
},
},
}

tmpDir := t.TempDir()
virtualFilesPath := fmt.Sprintf("%s/proc/sys/", tmpDir)
ipv4All := fmt.Sprintf("%s/net/ipv4/conf/all", virtualFilesPath)

setKernelVirtualFilesPath(virtualFilesPath)
err := os.MkdirAll(ipv4All, 0777)
req.NoError(err)
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
req := require.New(t)

err = os.WriteFile(fmt.Sprintf("%s/arp_ignore", ipv4All), []byte("0"), 0600)
req.NoError(err)
err = os.WriteFile(fmt.Sprintf("%s/arp_filter", ipv4All), []byte("1"), 0600)
req.NoError(err)
err = os.WriteFile(fmt.Sprintf("%s/arp_evict_nocarrier", ipv4All), []byte("1"), 0600)
req.NoError(err)
setExecStub(exec.Command("echo", "-n", test.cmdOut))

c := &CollectHostSysctl{
BundlePath: tmpDir,
}
tmpDir := t.TempDir()
c := &CollectHostSysctl{
BundlePath: tmpDir,
}

out, err := c.Collect(nil)
req.NoError(err)
res := CollectorResult(out)
reader, err := res.GetReader(tmpDir, HostSysctlPath)
req.NoError(err)
out, err := c.Collect(nil)
req.NoError(err)
res := CollectorResult(out)
reader, err := res.GetReader(tmpDir, HostSysctlPath)
req.NoError(err)

parameters := map[string]string{}
err = json.NewDecoder(reader).Decode(&parameters)
req.NoError(err)
parameters := map[string]string{}
err = json.NewDecoder(reader).Decode(&parameters)
req.NoError(err)

req.Equal(parameters, expectedOut)
req.Equal(test.expected, parameters)
})
}
}

func TestCollectHostSysctl_Title(t *testing.T) {
Expand Down

0 comments on commit 31172fb

Please sign in to comment.