feat: allow users to check cpu flags (#1631)

allow users to check if specific cpu flags are supported by the host.

```yaml
apiVersion: troubleshoot.sh/v1beta2
kind: HostPreflight
metadata:
  name: ec-cluster-preflight
spec:
  collectors:
  - cpu: {}
  analyzers:
  - cpu:
      checkName: CPU
      outcomes:
        - pass:
            when: hasFlags cmov,cx8,fpu,fxsr,mmx
            message: CPU supports all required flags
        - fail:
            message: CPU not supported
```
This commit is contained in:
Ricardo Maraschini
2024-10-01 10:48:25 +02:00
committed by GitHub
parent c1c4b612a4
commit 2efbc20b7c
2 changed files with 46 additions and 8 deletions

View File

@@ -15,14 +15,12 @@ import (
// ref: https://gitlab.com/x86-psABIs/x86-64-ABI
// ref: https://developers.redhat.com/blog/2021/01/05/building-red-hat-enterprise-linux-9-for-the-x86-64-v2-microarchitecture-level
var microarchs = map[string][]string{
"x86-64": {"cmov", "cx8", "fpu", "fxsr", "mmx", "syscall", "sse", "sse2"},
"x86-64-v2": {"cx16", "lahf_lm", "popcnt", "ssse3", "sse4_1", "sse4_2", "ssse3"},
"x86-64-v3": {"avx", "avx2", "bmi1", "bmi2", "f16c", "fma", "lzcnt", "movbe", "xsave"},
"x86-64-v4": {"avx512f", "avx512bw", "avx512cd", "avx512dq", "avx512vl"},
}
// x8664BaseFeatures are the features that are present in all x86-64 microarchitectures.
var x8664BaseFeatures = []string{"cmov", "cx8", "fpu", "fxsr", "mmx", "syscall", "sse", "sse2"}
type AnalyzeHostCPU struct {
hostAnalyzer *troubleshootv1beta2.CPUAnalyze
}
@@ -126,13 +124,36 @@ func (a *AnalyzeHostCPU) Analyze(
}
func doCompareHostCPUMicroArchitecture(microarch string, flags []string) (res bool, err error) {
specifics, ok := microarchs[microarch]
if !ok && microarch != "x86-64" {
specifics := make([]string, 0)
switch microarch {
case "x86-64-v4":
specifics = append(specifics, microarchs["x86-64-v4"]...)
fallthrough
case "x86-64-v3":
specifics = append(specifics, microarchs["x86-64-v3"]...)
fallthrough
case "x86-64-v2":
specifics = append(specifics, microarchs["x86-64-v2"]...)
fallthrough
case "x86-64":
specifics = append(specifics, microarchs["x86-64"]...)
default:
return false, errors.Errorf("troubleshoot does not yet support microarchitecture %q", microarch)
}
expectedFlags := x8664BaseFeatures
if len(specifics) > 0 {
expectedFlags = append(expectedFlags, specifics...)
for _, flag := range specifics {
if slices.Contains(flags, flag) {
continue
}
return false, nil
}
return true, nil
}
func doCompareHostCPUFlags(expected string, flags []string) (res bool, err error) {
expectedFlags := strings.Split(expected, ",")
if len(expectedFlags) == 0 {
return false, errors.New("expected flags cannot be empty")
}
for _, flag := range expectedFlags {
if slices.Contains(flags, flag) {
@@ -173,6 +194,11 @@ func compareHostCPUConditionalToActual(conditional string, logicalCount int, phy
return doCompareHostCPUMicroArchitecture(desired, flags)
}
// hasFlags allows users to query for specific flags on the CPU.
if strings.ToLower(comparator) == "hasflags" {
return doCompareHostCPUFlags(desired, flags)
}
if !compareLogical && !comparePhysical && !compareUnspecified {
return false, errors.New("unable to parse conditional")
}

View File

@@ -152,6 +152,18 @@ func Test_compareHostCPUConditionalToActual(t *testing.T) {
flags: []string{"cmov", "cx8", "fpu", "fxsr", "mmx", "syscall", "sse", "sse2", "cx16", "lahf_lm", "popcnt", "ssse3", "sse4_1", "sse4_2", "ssse3"},
expected: true,
},
{
name: "has a non existent flag",
when: "hasFlags cmov,doesNotExist",
flags: []string{"cmov", "cx8", "fpu", "fxsr", "mmx", "syscall", "sse", "sse2", "cx16", "lahf_lm", "popcnt", "ssse3", "sse4_1", "sse4_2", "ssse3"},
expected: false,
},
{
name: "has flags",
when: "hasFlags a,b,c",
flags: []string{"a", "b", "c", "d", "e"},
expected: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {