Skip to content

Commit

Permalink
feat(host_sysctl): add host sysctl collector (#1676)
Browse files Browse the repository at this point in the history
* feat(host_sysctl): add host sysctl collector

* chore: add examples

* Update pkg/collect/host_sysctl.go

Co-authored-by: Evans Mungai <[email protected]>

* chore: use sysctl package vs exec calls

* chore: make linter happy

* chore: make schemas

* chore: go back to sysctl exec

* chore: make linter happy

---------

Co-authored-by: Evans Mungai <[email protected]>
  • Loading branch information
JGAntunes and banjoh authored Nov 7, 2024
1 parent 06506ed commit 77c9968
Show file tree
Hide file tree
Showing 13 changed files with 357 additions and 0 deletions.
7 changes: 7 additions & 0 deletions config/crds/troubleshoot.sh_collectors.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17393,6 +17393,13 @@ spec:
- CIDRRangeAlloc
- desiredCIDR
type: object
sysctl:
properties:
collectorName:
type: string
exclude:
type: BoolString
type: object
systemPackages:
properties:
amzn:
Expand Down
7 changes: 7 additions & 0 deletions config/crds/troubleshoot.sh_hostcollectors.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1719,6 +1719,13 @@ spec:
- CIDRRangeAlloc
- desiredCIDR
type: object
sysctl:
properties:
collectorName:
type: string
exclude:
type: BoolString
type: object
systemPackages:
properties:
amzn:
Expand Down
7 changes: 7 additions & 0 deletions config/crds/troubleshoot.sh_hostpreflights.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1719,6 +1719,13 @@ spec:
- CIDRRangeAlloc
- desiredCIDR
type: object
sysctl:
properties:
collectorName:
type: string
exclude:
type: BoolString
type: object
systemPackages:
properties:
amzn:
Expand Down
7 changes: 7 additions & 0 deletions config/crds/troubleshoot.sh_supportbundles.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20366,6 +20366,13 @@ spec:
- CIDRRangeAlloc
- desiredCIDR
type: object
sysctl:
properties:
collectorName:
type: string
exclude:
type: BoolString
type: object
systemPackages:
properties:
amzn:
Expand Down
8 changes: 8 additions & 0 deletions examples/collect/host/sysctl.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: troubleshoot.sh/v1beta2
kind: HostCollector
metadata:
name: sysctl
spec:
collectors:
- sysctl:
collectorName: sysctl
10 changes: 10 additions & 0 deletions examples/preflight/host/sysctl.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: troubleshoot.sh/v1beta2
kind: HostPreflight
metadata:
name: sysctl
spec:
collectors:
- sysctl:
collectorName: sysctl
#TODO add analyzer once implemented
analyzers: []
5 changes: 5 additions & 0 deletions pkg/apis/troubleshoot/v1beta2/hostcollector_shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ type HostDNS struct {
Hostnames []string `json:"hostnames" yaml:"hostnames"`
}

type HostSysctl struct {
HostCollectorMeta `json:",inline" yaml:",inline"`
}

type HostCollect struct {
CPU *CPU `json:"cpu,omitempty" yaml:"cpu,omitempty"`
Memory *Memory `json:"memory,omitempty" yaml:"memory,omitempty"`
Expand Down Expand Up @@ -260,6 +264,7 @@ type HostCollect struct {
HostCGroups *HostCGroups `json:"cgroups,omitempty" yaml:"cgroups,omitempty"`
HostDNS *HostDNS `json:"dns,omitempty" yaml:"dns,omitempty"`
NetworkNamespaceConnectivity *HostNetworkNamespaceConnectivity `json:"networkNamespaceConnectivity,omitempty" yaml:"networkNamespaceConnectivity,omitempty"`
HostSysctl *HostSysctl `json:"sysctl,omitempty" yaml:"sysctl,omitempty"`
}

// GetName gets the name of the collector
Expand Down
21 changes: 21 additions & 0 deletions pkg/apis/troubleshoot/v1beta2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pkg/collect/host_collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ func GetHostCollector(collector *troubleshootv1beta2.HostCollect, bundlePath str
return &CollectHostDNS{collector.HostDNS, bundlePath}, true
case collector.NetworkNamespaceConnectivity != nil:
return &CollectHostNetworkNamespaceConnectivity{collector.NetworkNamespaceConnectivity, bundlePath}, true
case collector.HostSysctl != nil:
return &CollectHostSysctl{collector.HostSysctl, bundlePath}, true
default:
return nil, false
}
Expand Down
88 changes: 88 additions & 0 deletions pkg/collect/host_sysctl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package collect

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

"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)

// Helper var to allow stubbing `exec.Command` for tests
var execCommand = exec.Command

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

type CollectHostSysctl struct {
hostCollector *troubleshootv1beta2.HostSysctl
BundlePath string
}

func (c *CollectHostSysctl) Title() string {
return hostCollectorTitleOrDefault(c.hostCollector.HostCollectorMeta, "Sysctl")
}

func (c *CollectHostSysctl) IsExcluded() (bool, error) {
return isExcluded(c.hostCollector.Exclude)
}

func (c *CollectHostSysctl) Collect(progressChan chan<- interface{}) (map[string][]byte, error) {
klog.V(2).Info("Running sysctl collector")
cmd := execCommand("sysctl", "-a")
out, err := cmd.Output()
if err != nil {
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)

switch len(matches) {
// there are no matches for the value and separator, ignore and log
case 0, 1, 2:
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
case 3:
klog.V(2).Infof("found no value for sysctl line, keeping it with an empty value: %s", l)
result[matches[1]] = ""
default:
result[matches[1]] = matches[3]
}
}
return result
}
Loading

0 comments on commit 77c9968

Please sign in to comment.