Skip to content

Commit

Permalink
add selectedConfigs field
Browse files Browse the repository at this point in the history
  • Loading branch information
nvanthao committed May 24, 2024
1 parent add21c3 commit 2c34fda
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 149 deletions.
5 changes: 5 additions & 0 deletions config/crds/troubleshoot.sh_analyzers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2343,10 +2343,15 @@ spec:
type: object
type: object
type: array
selectedConfigs:
items:
type: string
type: array
strict:
type: BoolString
required:
- outcomes
- selectedConfigs
type: object
kernelModules:
properties:
Expand Down
5 changes: 5 additions & 0 deletions config/crds/troubleshoot.sh_hostcollectors.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -632,10 +632,15 @@ spec:
type: object
type: object
type: array
selectedConfigs:
items:
type: string
type: array
strict:
type: BoolString
required:
- outcomes
- selectedConfigs
type: object
kernelModules:
properties:
Expand Down
5 changes: 5 additions & 0 deletions config/crds/troubleshoot.sh_hostpreflights.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -632,10 +632,15 @@ spec:
type: object
type: object
type: array
selectedConfigs:
items:
type: string
type: array
strict:
type: BoolString
required:
- outcomes
- selectedConfigs
type: object
kernelModules:
properties:
Expand Down
5 changes: 5 additions & 0 deletions config/crds/troubleshoot.sh_supportbundles.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19182,10 +19182,15 @@ spec:
type: object
type: object
type: array
selectedConfigs:
items:
type: string
type: array
strict:
type: BoolString
required:
- outcomes
- selectedConfigs
type: object
kernelModules:
properties:
Expand Down
101 changes: 41 additions & 60 deletions pkg/analyze/host_kernel_configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package analyzer

import (
"encoding/json"
"regexp"

"strings"

"github.com/pkg/errors"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/collect"
"github.com/replicatedhq/troubleshoot/pkg/constants"
"k8s.io/klog/v2"
)

type AnalyzeHostKernelConfigs struct {
Expand Down Expand Up @@ -37,80 +39,59 @@ func (a *AnalyzeHostKernelConfigs) Analyze(
return nil, errors.Wrap(err, "failed to read kernel configs")
}

var results []*AnalyzeResult
for _, outcome := range hostAnalyzer.Outcomes {
result := &AnalyzeResult{
Title: a.Title(),
Strict: hostAnalyzer.Strict.BoolOrDefaultFalse(),
var configsNotFound []string
kConfigRegex := regexp.MustCompile("^(CONFIG_[A-Z0-9_]+)=([ymn])$")
for _, config := range hostAnalyzer.SelectedConfigs {
matches := kConfigRegex.FindStringSubmatch(config)
// zero tolerance for invalid kernel config
if matches == nil || len(matches) < 3 {
return nil, errors.Errorf("invalid kernel config: %s", config)
}

if err := analyzeSingleOutcome(kConfigs, result, outcome.Pass, constants.OUTCOME_PASS); err != nil {
return nil, errors.Wrap(err, "failed to analyze pass outcome")
}
key := matches[1]
value := matches[2]

if err := analyzeSingleOutcome(kConfigs, result, outcome.Fail, constants.OUTCOME_FAIL); err != nil {
return nil, errors.Wrap(err, "failed to analyze fail outcome")
// check if the kernel config exists
if _, ok := kConfigs[key]; !ok {
configsNotFound = append(configsNotFound, config)
continue
}

if err := analyzeSingleOutcome(kConfigs, result, outcome.Warn, constants.OUTCOME_WARN); err != nil {
return nil, errors.Wrap(err, "failed to analyze warn outcome")
// check if the kernel config value matches
if kConfigs[key] != value {
klog.V(2).Infof("collected kernel config %s=%s does not match expected value %s", key, kConfigs[key], value)
configsNotFound = append(configsNotFound, config)
}

results = append(results, result)
}

return results, nil
}

func analyzeSingleOutcome(kConfigs collect.KConfigs, result *AnalyzeResult, outcome *troubleshootv1beta2.SingleOutcome, outcomeType string) error {
if outcome == nil {
return nil
}

if outcome.When == "" {
return errors.New("when attribute is required")
}

isMatch, err := match(kConfigs, outcome.When)
if err != nil {
return errors.Wrap(err, "failed to match")
}
var results []*AnalyzeResult
for _, outcome := range hostAnalyzer.Outcomes {
result := &AnalyzeResult{
Title: a.Title(),
Strict: hostAnalyzer.Strict.BoolOrDefaultFalse(),
}

result.Message = outcome.Message
result.URI = outcome.URI
if outcome.Pass != nil && len(configsNotFound) == 0 {
result.IsPass = true
result.Message = outcome.Pass.Message
results = append(results, result)
break
}

// if no match, set pass outcome to fail
if !isMatch {
if outcomeType == constants.OUTCOME_PASS {
if outcome.Fail != nil && len(configsNotFound) > 0 {
result.IsFail = true
result.Message = addMissingKernelConfigs(outcome.Fail.Message, configsNotFound)
results = append(results, result)
break
}
return nil
}

switch outcomeType {
case constants.OUTCOME_PASS:
result.IsPass = true
case constants.OUTCOME_FAIL:
result.IsFail = true
case constants.OUTCOME_WARN:
result.IsWarn = true
}

return nil
return results, nil
}

func match(kConfigs collect.KConfigs, when string) (bool, error) {
parts := strings.SplitN(when, "=", 2)
if len(parts) != 2 {
return false, errors.New("invalid when attribute")
func addMissingKernelConfigs(message string, missingConfigs []string) string {
if message == "" && len(missingConfigs) == 0 {
return message
}
key, value := parts[0], parts[1]

// check if the key exists
if kConfig, ok := kConfigs[key]; ok {
return kConfig == strings.TrimSpace(value), nil
}

// kernel config not found
return false, nil
return strings.ReplaceAll(message, "{{ .ConfigsNotFound }}", strings.Join(missingConfigs, ", "))
}
112 changes: 28 additions & 84 deletions pkg/analyze/host_kernel_configs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,135 +15,78 @@ func TestAnalyzeKernelConfigs(t *testing.T) {
}

tests := []struct {
name string
kConfigs collect.KConfigs
outcomes []*troubleshootv1beta2.Outcome
results []*AnalyzeResult
expectErr bool
name string
kConfigs collect.KConfigs
selectedConfigs []string
outcomes []*troubleshootv1beta2.Outcome
results []*AnalyzeResult
expectErr bool
}{
{
name: "all pass",
kConfigs: kConfigs,
name: "all pass",
kConfigs: kConfigs,
selectedConfigs: []string{"CONFIG_CGROUP_FREEZER=y", "CONFIG_NETFILTER_XTABLES=m"},
outcomes: []*troubleshootv1beta2.Outcome{
{
Pass: &troubleshootv1beta2.SingleOutcome{
When: "CONFIG_CGROUP_FREEZER=y",
Message: "Freezer cgroup subsystem built-in",
},
},
{
Pass: &troubleshootv1beta2.SingleOutcome{
When: "CONFIG_NETFILTER_XTABLES=m",
Message: "Netfilter Xtables support module",
Message: "required kernel configs are available",
},
},
},
results: []*AnalyzeResult{
{
Title: "Kernel Configs",
IsPass: true,
Message: "Freezer cgroup subsystem built-in",
}, {
Title: "Kernel Configs",
IsPass: true,
Message: "Netfilter Xtables support module",
Message: "required kernel configs are available",
},
},
expectErr: false,
},
{
name: "has fail",
kConfigs: kConfigs,
name: "has fail",
kConfigs: kConfigs,
selectedConfigs: []string{"CONFIG_UTS_NS=y"},
outcomes: []*troubleshootv1beta2.Outcome{
{
Fail: &troubleshootv1beta2.SingleOutcome{
When: "CONFIG_NETFILTER_XTABLES=m",
Message: "Netfilter Xtables support module",
},
},
},
results: []*AnalyzeResult{
{
Title: "Kernel Configs",
IsFail: true,
Message: "Netfilter Xtables support module",
},
},
expectErr: false,
},
{
name: "has warn",
kConfigs: kConfigs,
outcomes: []*troubleshootv1beta2.Outcome{
{
Warn: &troubleshootv1beta2.SingleOutcome{
When: "CONFIG_NETFILTER_XTABLES=m",
Message: "Netfilter Xtables support module",
},
},
},
results: []*AnalyzeResult{
{
Title: "Kernel Configs",
IsWarn: true,
Message: "Netfilter Xtables support module",
},
},
expectErr: false,
},
{
name: "missing kernel config",
kConfigs: kConfigs,
outcomes: []*troubleshootv1beta2.Outcome{
{
Pass: &troubleshootv1beta2.SingleOutcome{
When: "CONFIG_NF_NAT_IPV4=y",
Message: "IPv4 NAT option",
Message: "missing kernel config(s): {{ .ConfigsNotFound }}",
},
},
},
results: []*AnalyzeResult{
{
Title: "Kernel Configs",
IsPass: false,
IsFail: true,
Message: "IPv4 NAT option",
Message: "missing kernel config(s): CONFIG_UTS_NS=y",
},
},
expectErr: false,
},
{
name: "kernel config disabled",
kConfigs: kConfigs,
name: "kernel config disabled",
kConfigs: kConfigs,
selectedConfigs: []string{"CONFIG_CGROUP_FREEZER=n"},
outcomes: []*troubleshootv1beta2.Outcome{
{
Pass: &troubleshootv1beta2.SingleOutcome{
When: "CONFIG_CGROUP_FREEZER=n",
Message: "CONFIG_CGROUP_FREEZER is disabled",
Fail: &troubleshootv1beta2.SingleOutcome{
Message: "missing kernel config(s): {{ .ConfigsNotFound }}",
},
},
},
results: []*AnalyzeResult{
{
Title: "Kernel Configs",
IsPass: false,
IsFail: true,
Message: "CONFIG_CGROUP_FREEZER is disabled",
Message: "missing kernel config(s): CONFIG_CGROUP_FREEZER=n",
},
},
expectErr: false,
},
{
name: "missing when attribute",
outcomes: []*troubleshootv1beta2.Outcome{
{
Pass: &troubleshootv1beta2.SingleOutcome{
Message: "CONFIG_foo is enabled",
When: "",
},
},
},
expectErr: true,
name: "invalid kernel config",
kConfigs: kConfigs,
selectedConfigs: []string{"foobar=n"},
expectErr: true,
},
}

Expand All @@ -159,7 +102,8 @@ func TestAnalyzeKernelConfigs(t *testing.T) {
AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{
CheckName: "Kernel Configs",
},
Outcomes: tt.outcomes,
SelectedConfigs: tt.selectedConfigs,
Outcomes: tt.outcomes,
},
}

Expand Down
7 changes: 4 additions & 3 deletions pkg/apis/troubleshoot/v1beta2/hostanalyzer_shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,10 @@ type HostOSAnalyze struct {
}

type KernelConfigsAnalyze struct {
AnalyzeMeta `json:",inline" yaml:",inline"`
CollectorName string `json:"collectorName,omitempty" yaml:"collectorName,omitempty"`
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
AnalyzeMeta `json:",inline" yaml:",inline"`
CollectorName string `json:"collectorName,omitempty" yaml:"collectorName,omitempty"`
SelectedConfigs []string `json:"selectedConfigs" yaml:"selectedConfigs"`
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
}

type HostAnalyze struct {
Expand Down
Loading

0 comments on commit 2c34fda

Please sign in to comment.