From 1fad8f50834d51e245fc6d0a850976a756e7d36e Mon Sep 17 00:00:00 2001 From: Huang Huang Date: Mon, 10 Jan 2022 21:25:15 +0800 Subject: [PATCH] Update auto-detection codes to support check platform version (#1074) Co-authored-by: Yoav Rotem --- cmd/common.go | 6 ++--- cmd/common_test.go | 30 ++++++++++----------- cmd/master.go | 2 +- cmd/node.go | 2 +- cmd/root.go | 2 +- cmd/run.go | 2 +- cmd/util.go | 65 ++++++++++++++++++++++++++++++---------------- cmd/util_test.go | 49 +++++++++++++++++++++------------- 8 files changed, 95 insertions(+), 63 deletions(-) diff --git a/cmd/common.go b/cmd/common.go index 60f291332..6fb72ae1a 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -313,13 +313,13 @@ func loadTargetMapping(v *viper.Viper) (map[string][]string, error) { return benchmarkVersionToTargetsMap, nil } -func getBenchmarkVersion(kubeVersion, benchmarkVersion, platformName string, v *viper.Viper) (bv string, err error) { +func getBenchmarkVersion(kubeVersion, benchmarkVersion string, platform Platform, v *viper.Viper) (bv string, err error) { detecetedKubeVersion = "none" if !isEmpty(kubeVersion) && !isEmpty(benchmarkVersion) { return "", fmt.Errorf("It is an error to specify both --version and --benchmark flags") } - if isEmpty(benchmarkVersion) && isEmpty(kubeVersion) && !isEmpty(platformName) { - benchmarkVersion = getPlatformBenchmarkVersion(platformName) + if isEmpty(benchmarkVersion) && isEmpty(kubeVersion) && !isEmpty(platform.Name) { + benchmarkVersion = getPlatformBenchmarkVersion(platform) if !isEmpty(benchmarkVersion) { detecetedKubeVersion = benchmarkVersion } diff --git a/cmd/common_test.go b/cmd/common_test.go index e4249880d..04c8cb35e 100644 --- a/cmd/common_test.go +++ b/cmd/common_test.go @@ -324,9 +324,9 @@ func TestGetBenchmarkVersion(t *testing.T) { t.Fatalf("Unable to load config file %v", err) } - type getBenchmarkVersionFnToTest func(kubeVersion, benchmarkVersion, platformName string, v *viper.Viper) (string, error) + type getBenchmarkVersionFnToTest func(kubeVersion, benchmarkVersion string, platform Platform, v *viper.Viper) (string, error) - withFakeKubectl := func(kubeVersion, benchmarkVersion, platformName string, v *viper.Viper, fn getBenchmarkVersionFnToTest) (string, error) { + withFakeKubectl := func(kubeVersion, benchmarkVersion string, platform Platform, v *viper.Viper, fn getBenchmarkVersionFnToTest) (string, error) { execCode := `#!/bin/sh echo '{"serverVersion": {"major": "1", "minor": "18", "gitVersion": "v1.18.10"}}' ` @@ -336,40 +336,40 @@ func TestGetBenchmarkVersion(t *testing.T) { } defer restore() - return fn(kubeVersion, benchmarkVersion, platformName, v) + return fn(kubeVersion, benchmarkVersion, platform, v) } - withNoPath := func(kubeVersion, benchmarkVersion, platformName string, v *viper.Viper, fn getBenchmarkVersionFnToTest) (string, error) { + withNoPath := func(kubeVersion, benchmarkVersion string, platform Platform, v *viper.Viper, fn getBenchmarkVersionFnToTest) (string, error) { restore, err := prunePath() if err != nil { t.Fatal("Failed when calling prunePath ", err) } defer restore() - return fn(kubeVersion, benchmarkVersion, platformName, v) + return fn(kubeVersion, benchmarkVersion, platform, v) } - type getBenchmarkVersionFn func(string, string, string, *viper.Viper, getBenchmarkVersionFnToTest) (string, error) + type getBenchmarkVersionFn func(string, string, Platform, *viper.Viper, getBenchmarkVersionFnToTest) (string, error) cases := []struct { n string kubeVersion string benchmarkVersion string - platformName string + platform Platform v *viper.Viper callFn getBenchmarkVersionFn exp string succeed bool }{ - {n: "both versions", kubeVersion: "1.11", benchmarkVersion: "cis-1.3", platformName: "", exp: "cis-1.3", callFn: withNoPath, v: viper.New(), succeed: false}, - {n: "no version-missing-kubectl", kubeVersion: "", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "cis-1.6", callFn: withNoPath, succeed: true}, - {n: "no version-fakeKubectl", kubeVersion: "", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "cis-1.6", callFn: withFakeKubectl, succeed: true}, - {n: "kubeVersion", kubeVersion: "1.15", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "cis-1.5", callFn: withNoPath, succeed: true}, - {n: "ocpVersion310", kubeVersion: "ocp-3.10", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "rh-0.7", callFn: withNoPath, succeed: true}, - {n: "ocpVersion311", kubeVersion: "ocp-3.11", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "rh-0.7", callFn: withNoPath, succeed: true}, - {n: "gke12", kubeVersion: "gke-1.2.0", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "gke-1.2.0", callFn: withNoPath, succeed: true}, + {n: "both versions", kubeVersion: "1.11", benchmarkVersion: "cis-1.3", platform: Platform{}, exp: "cis-1.3", callFn: withNoPath, v: viper.New(), succeed: false}, + {n: "no version-missing-kubectl", kubeVersion: "", benchmarkVersion: "", platform: Platform{}, v: viperWithData, exp: "cis-1.6", callFn: withNoPath, succeed: true}, + {n: "no version-fakeKubectl", kubeVersion: "", benchmarkVersion: "", platform: Platform{}, v: viperWithData, exp: "cis-1.6", callFn: withFakeKubectl, succeed: true}, + {n: "kubeVersion", kubeVersion: "1.15", benchmarkVersion: "", platform: Platform{}, v: viperWithData, exp: "cis-1.5", callFn: withNoPath, succeed: true}, + {n: "ocpVersion310", kubeVersion: "ocp-3.10", benchmarkVersion: "", platform: Platform{}, v: viperWithData, exp: "rh-0.7", callFn: withNoPath, succeed: true}, + {n: "ocpVersion311", kubeVersion: "ocp-3.11", benchmarkVersion: "", platform: Platform{}, v: viperWithData, exp: "rh-0.7", callFn: withNoPath, succeed: true}, + {n: "gke12", kubeVersion: "gke-1.2.0", benchmarkVersion: "", platform: Platform{}, v: viperWithData, exp: "gke-1.2.0", callFn: withNoPath, succeed: true}, } for _, c := range cases { - rv, err := c.callFn(c.kubeVersion, c.benchmarkVersion, c.platformName, c.v, getBenchmarkVersion) + rv, err := c.callFn(c.kubeVersion, c.benchmarkVersion, c.platform, c.v, getBenchmarkVersion) if c.succeed { if err != nil { t.Errorf("[%q]-Unexpected error: %v", c.n, err) diff --git a/cmd/master.go b/cmd/master.go index 7b977e2f7..99d9cb38a 100644 --- a/cmd/master.go +++ b/cmd/master.go @@ -28,7 +28,7 @@ var masterCmd = &cobra.Command{ Short: "Run Kubernetes benchmark checks from the master.yaml file.", Long: `Run Kubernetes benchmark checks from the master.yaml file in cfg/.`, Run: func(cmd *cobra.Command, args []string) { - bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformName(), viper.GetViper()) + bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformInfo(), viper.GetViper()) if err != nil { exitWithError(fmt.Errorf("unable to determine benchmark version: %v", err)) } diff --git a/cmd/node.go b/cmd/node.go index 73a731ecd..5672297d2 100644 --- a/cmd/node.go +++ b/cmd/node.go @@ -28,7 +28,7 @@ var nodeCmd = &cobra.Command{ Short: "Run Kubernetes benchmark checks from the node.yaml file.", Long: `Run Kubernetes benchmark checks from the node.yaml file in cfg/.`, Run: func(cmd *cobra.Command, args []string) { - bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformName(), viper.GetViper()) + bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformInfo(), viper.GetViper()) if err != nil { exitWithError(fmt.Errorf("unable to determine benchmark version: %v", err)) } diff --git a/cmd/root.go b/cmd/root.go index 99b802ddb..785d021f3 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -69,7 +69,7 @@ var RootCmd = &cobra.Command{ Short: "Run CIS Benchmarks checks against a Kubernetes deployment", Long: `This tool runs the CIS Kubernetes Benchmark (https://www.cisecurity.org/benchmark/kubernetes/)`, Run: func(cmd *cobra.Command, args []string) { - bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformName(), viper.GetViper()) + bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformInfo(), viper.GetViper()) if err != nil { exitWithError(fmt.Errorf("unable to determine benchmark version: %v", err)) } diff --git a/cmd/run.go b/cmd/run.go index ccd56de26..db92fe73c 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -32,7 +32,7 @@ var runCmd = &cobra.Command{ exitWithError(fmt.Errorf("unable to get `targets` from command line :%v", err)) } - bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformName(), viper.GetViper()) + bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformInfo(), viper.GetViper()) if err != nil { exitWithError(fmt.Errorf("unable to get benchmark version. error: %v", err)) } diff --git a/cmd/util.go b/cmd/util.go index 200437140..365d5ef9f 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -42,6 +42,15 @@ func init() { getBinariesFunc = getBinaries } +type Platform struct { + Name string + Version string +} + +func (p Platform) String() string { + return fmt.Sprintf("Platform{ Name: %s Version: %s }", p.Name, p.Version) +} + func exitWithError(err error) { fmt.Fprintf(os.Stderr, "\n%v\n", err) // flush before exit non-zero @@ -427,49 +436,59 @@ These program names are provided in the config.yaml, section '%s.%s.bins' return fmt.Sprintf(errMessageTemplate, component, componentRoleName, binList, componentType, component) } -func getPlatformName() string { +func getPlatformInfo() Platform { - openShiftVersion := getOpenShiftVersion() - if openShiftVersion != "" { - return openShiftVersion + openShiftInfo := getOpenShiftInfo() + if openShiftInfo.Name != "" && openShiftInfo.Version != "" { + return openShiftInfo } kv, err := getKubeVersion() if err != nil { glog.V(2).Info(err) - return "" + return Platform{} } - return getPlatformNameFromVersion(kv.GitVersion) + return getPlatformInfoFromVersion(kv.GitVersion) } -func getPlatformNameFromVersion(s string) string { - versionRe := regexp.MustCompile(`v\d+\.\d+\.\d+-(\w+)(?:[.\-])\w+`) +func getPlatformInfoFromVersion(s string) Platform { + versionRe := regexp.MustCompile(`v(\d+\.\d+)\.\d+-(\w+)(?:[.\-])\w+`) subs := versionRe.FindStringSubmatch(s) - if len(subs) < 2 { - return "" + if len(subs) < 3 { + return Platform{} + } + return Platform{ + Name: subs[2], + Version: subs[1], } - return subs[1] } -func getPlatformBenchmarkVersion(platform string) string { +func getPlatformBenchmarkVersion(platform Platform) string { glog.V(3).Infof("getPlatformBenchmarkVersion platform: %s", platform) - switch platform { + switch platform.Name { case "eks": return "eks-1.0.1" case "gke": - // TODO: support check kubeVersion - return "gke-1.2.0" + switch platform.Version { + case "1.15", "1.16", "1.17", "1.18", "1.19": + return "gke-1.0" + default: + return "gke-1.2.0" + } case "aliyun": return "ack-1.0" - case "ocp-3.10": - return "rh-0.7" - case "ocp-4.1": - return "rh-1.0" + case "ocp": + switch platform.Version { + case "3.10": + return "rh-0.7" + case "4.1": + return "rh-1.0" + } } return "" } -func getOpenShiftVersion() string { +func getOpenShiftInfo() Platform { glog.V(1).Info("Checking for oc") _, err := exec.LookPath("oc") @@ -485,10 +504,10 @@ func getOpenShiftVersion() string { subs = versionRe.FindStringSubmatch(string(out)) } if len(subs) > 1 { - glog.V(2).Infof("OCP output '%s' \nplatform is %s \nocp %v", string(out), getPlatformNameFromVersion(string(out)), subs[1]) + glog.V(2).Infof("OCP output '%s' \nplatform is %s \nocp %v", string(out), getPlatformInfoFromVersion(string(out)), subs[1]) ocpBenchmarkVersion, err := getOcpValidVersion(subs[1]) if err == nil { - return fmt.Sprintf("ocp-%s", ocpBenchmarkVersion) + return Platform{Name: "ocp", Version: ocpBenchmarkVersion} } else { glog.V(1).Infof("Can't get getOcpValidVersion: %v", err) } @@ -501,7 +520,7 @@ func getOpenShiftVersion() string { } else { glog.V(1).Infof("Can't find oc command: %v", err) } - return "" + return Platform{} } func getOcpValidVersion(ocpVer string) (string, error) { diff --git a/cmd/util_test.go b/cmd/util_test.go index 45b4c24a3..4d88abc87 100644 --- a/cmd/util_test.go +++ b/cmd/util_test.go @@ -527,46 +527,45 @@ func Test_getPlatformNameFromKubectlOutput(t *testing.T) { tests := []struct { name string args args - want string + want Platform }{ { name: "eks", args: args{s: "v1.17.9-eks-4c6976"}, - want: "eks", + want: Platform{Name: "eks", Version: "1.17"}, }, { name: "gke", args: args{s: "v1.17.6-gke.1"}, - want: "gke", + want: Platform{Name: "gke", Version: "1.17"}, }, { name: "ack", args: args{s: "v1.18.8-aliyun.1"}, - want: "aliyun", + want: Platform{Name: "aliyun", Version: "1.18"}, }, { name: "unknown", args: args{s: "v1.17.6"}, - want: "", + want: Platform{}, }, { name: "empty string", args: args{s: ""}, - want: "", + want: Platform{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := getPlatformNameFromVersion(tt.args.s); got != tt.want { - t.Errorf("getPlatformNameFromKubectlOutput() = %v, want %v", got, tt.want) - } + got := getPlatformInfoFromVersion(tt.args.s) + assert.Equal(t, tt.want, got) }) } } func Test_getPlatformBenchmarkVersion(t *testing.T) { type args struct { - platform string + platform Platform } tests := []struct { name string @@ -576,49 +575,63 @@ func Test_getPlatformBenchmarkVersion(t *testing.T) { { name: "eks", args: args{ - platform: "eks", + platform: Platform{Name: "eks"}, }, want: "eks-1.0.1", }, { - name: "gke", + name: "gke 1.19", + args: args{ + platform: Platform{Name: "gke", Version: "1.19"}, + }, + want: "gke-1.0", + }, + { + name: "gke 1.20", + args: args{ + platform: Platform{Name: "gke", Version: "1.20"}, + }, + want: "gke-1.2.0", + }, + { + name: "gke 1.22", args: args{ - platform: "gke", + platform: Platform{Name: "gke", Version: "1.22"}, }, want: "gke-1.2.0", }, { name: "aliyun", args: args{ - platform: "aliyun", + platform: Platform{Name: "aliyun"}, }, want: "ack-1.0", }, { name: "unknown", args: args{ - platform: "rh", + platform: Platform{Name: "rh"}, }, want: "", }, { name: "empty", args: args{ - platform: "", + platform: Platform{}, }, want: "", }, { name: "openshift3", args: args{ - platform: "ocp-3.10", + platform: Platform{Name: "ocp", Version: "3.10"}, }, want: "rh-0.7", }, { name: "openshift4", args: args{ - platform: "ocp-4.1", + platform: Platform{Name: "ocp", Version: "4.1"}, }, want: "rh-1.0", },