Skip to content

Commit

Permalink
feat: support config and spec version flags (#130)
Browse files Browse the repository at this point in the history
* feat: support config and spec version flags

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: support config and spec version flags

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: support config and spec version flags

Signed-off-by: chenk <hen.keinan@gmail.com>

---------

Signed-off-by: chenk <hen.keinan@gmail.com>
  • Loading branch information
chen-keinan authored May 23, 2024
1 parent 871c783 commit 74a24dd
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 73 deletions.
14 changes: 11 additions & 3 deletions job.yaml

Large diffs are not rendered by default.

117 changes: 75 additions & 42 deletions pkg/collector/collect.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (

"github.com/Masterminds/semver"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)

const (
Expand Down Expand Up @@ -44,7 +45,9 @@ func CollectData(cmd *cobra.Command) error {
if err != nil {
return err
}
lp, err := LoadConfigParams()
nodeFileconfig := cmd.Flag("node-config").Value.String()
specVersionMapping := cmd.Flag("spec-version-mapping").Value.String()
lp, mp, err := LoadConfigParams(nodeFileconfig, specVersionMapping)
if err != nil {
return err
}
Expand All @@ -53,59 +56,89 @@ func CollectData(cmd *cobra.Command) error {
if err != nil {
return err
}
sv, err := specID(cmd, cluster, lp)
specName := cmd.Flag("spec-name").Value.String()
specVersion := cmd.Flag("spec-version").Value.String()
clusterVersion := cmd.Flag("cluster-version").Value.String()
sv, err := specID(specName, specVersion, clusterVersion, cluster, mp)
if err != nil {
return err
}
for _, infoCollector := range infoCollectorMap {
nodeInfo := make(map[string]*Info)
if fmt.Sprintf("%s-%s", infoCollector.Name, infoCollector.Version) != sv {
continue
}
for _, ci := range infoCollector.Collectors {
if ci.NodeType != nodeType && nodeType != MasterNode {
continue
}
output, err := shellCmd.Execute(ci.Audit)
nodeCommands := cmd.Flag("node-commands").Value.String()
commands, err := GetNodesCommands(nodeCommands, infoCollectorMap, nodeType, sv)
if len(commands) == 0 {
return fmt.Errorf("spec not found")
}
nodeInfo, err := ExecuteCommands(shellCmd, commands)
if err != nil {
return err
}
nodeName := cmd.Flag("node").Value.String()
kubeletConfig := cmd.Flag("kubelet-config").Value.String()
if nodeName != "" || kubeletConfig != "" {
nodeConfig, err := loadNodeConfig(ctx, *cluster, nodeName, kubeletConfig)
if err == nil {
kubeletConfigMapping := cmd.Flag("kubelet-config-mapping").Value.String()
mapping, err := LoadKubeletMapping(kubeletConfigMapping)
if err != nil {
return err
}
values := StringToArray(output, ",")
nodeInfo[ci.Key] = &Info{Values: values}
configVal := getValuesFromkubeletConfig(nodeConfig, mapping)
mergeConfigValues(nodeInfo, configVal)
}
nodeName := cmd.Flag("node").Value.String()
kubeletConfig := cmd.Flag("kubelet-config").Value.String()
if nodeName != "" || kubeletConfig != "" {
nodeConfig, err := loadNodeConfig(ctx, *cluster, nodeName, kubeletConfig)
if err == nil {
mapping, err := LoadKubeletMapping()
if err != nil {
return err
}
configVal := getValuesFromkubeletConfig(nodeConfig, mapping)
mergeConfigValues(nodeInfo, configVal)
}
}
nodeData := Node{
APIVersion: Version,
Kind: Kind,
Type: nodeType,
Metadata: map[string]string{"creationTimestamp": time.Now().Format(time.RFC3339)},
Info: nodeInfo,
}
outputFormat := cmd.Flag("output").Value.String()
err = printOutput(nodeData, outputFormat, os.Stdout)
if err != nil {
return err
}
return nil
}

func GetNodesCommands(nodeCommands string, infoCollectorMap map[string]*SpecInfo, nodeType string, sv string) ([]Command, error) {
var commands []Command
var specInfo SpecInfo
if nodeCommands != "" {
base64Commands, err := base64.StdEncoding.DecodeString(nodeCommands)
if err != nil {
return nil, err
}
nodeData := Node{
APIVersion: Version,
Kind: Kind,
Type: nodeType,
Metadata: map[string]string{"creationTimestamp": time.Now().Format(time.RFC3339)},
Info: nodeInfo,
err = yaml.Unmarshal(base64Commands, &specInfo)
if err != nil {
return nil, err
}
commands = specInfo.Commands
} else {
for _, infoCollector := range infoCollectorMap {
if fmt.Sprintf("%s-%s", infoCollector.Name, infoCollector.Version) == sv {
commands = infoCollector.Commands
break
}
}
outputFormat := cmd.Flag("output").Value.String()
err = printOutput(nodeData, outputFormat, os.Stdout)
}
return commands, nil
}

func ExecuteCommands(shellCmd Shell, ci []Command) (map[string]*Info, error) {
nodeInfo := make(map[string]*Info)
for _, c := range ci {
output, err := shellCmd.Execute(c.Audit)
if err != nil {
return err
return nil, err
}
values := StringToArray(output, ",")
nodeInfo[c.Key] = &Info{Values: values}
}
return nil
return nodeInfo, nil
}

func specID(cmd *cobra.Command, cluster *Cluster, lp *Config) (string, error) {
specName := cmd.Flag("spec-name").Value.String()
specVersion := cmd.Flag("spec-version").Value.String()
clusterVersion := cmd.Flag("cluster-version").Value.String()
func specID(specName, specVersion, clusterVersion string, cluster *Cluster, mp *Mapper) (string, error) {
switch {
case specName != "" && specVersion != "":
return fmt.Sprintf("%s-%s", specName, specVersion), nil
Expand All @@ -115,13 +148,13 @@ func specID(cmd *cobra.Command, cluster *Cluster, lp *Config) (string, error) {
Name: strings.TrimSuffix(specName, "-cis"),
Version: majorVersion(clusterVersion),
},
lp.VersionMapping), nil
mp.VersionMapping), nil
default: // auto detect spec by platform type (k8s, aks, eks and etc) and version
p, err := cluster.Platfrom()
if err != nil {
return "", err
}
return specByPlatfromVersion(p, lp.VersionMapping), nil
return specByPlatfromVersion(p, mp.VersionMapping), nil
}
}

Expand Down
38 changes: 34 additions & 4 deletions pkg/collector/collect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package collector
import (
"encoding/json"
"os"
"reflect"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -57,7 +58,7 @@ func TestParseNodeConfig(t *testing.T) {
nodeConfig := make(map[string]interface{})
err = json.Unmarshal(data, &nodeConfig)
assert.NoError(t, err)
mapping, err := LoadKubeletMapping()
mapping, err := LoadKubeletMapping("")
assert.NoError(t, err)
m := getValuesFromkubeletConfig(nodeConfig, mapping)
for k, v := range m {
Expand Down Expand Up @@ -118,10 +119,10 @@ func TestSpecByVersionName(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
f, err := os.ReadFile(tt.versionMappingfile)
assert.NoError(t, err)
var config Config
err = yaml.Unmarshal(f, &config)
var mapper Mapper
err = yaml.Unmarshal(f, &mapper)
assert.NoError(t, err)
gotSpec := specByPlatfromVersion(tt.platfrom, config.VersionMapping)
gotSpec := specByPlatfromVersion(tt.platfrom, mapper.VersionMapping)
assert.Equal(t, gotSpec, tt.wantSpec)
})
}
Expand Down Expand Up @@ -172,3 +173,32 @@ func TestPlatfromVersion(t *testing.T) {
})
}
}

func TestNodeCommamnd(t *testing.T) {
tests := []struct {
name string
commands string
want []Command
}{
{
name: "k8s version",
commands: "LS0tCmNvbW1hbmRzOgogIC0ga2V5OiBrdWJlQVBJU2VydmVyU3BlY0ZpbGVQZXJtaXNzaW9uCiAgICB0aXRsZTogQVBJIHNlcnZlciBwb2Qgc3BlY2lmaWNhdGlvbiBmaWxlIHBlcm1pc3Npb25zCiAgICBub2RlVHlwZTogbWFzdGVyCiAgICBhdWRpdDogc3RhdCAtYyAlYSAkYXBpc2VydmVyLmNvbmZzCgo=",
want: []Command{
{
Key: "kubeAPIServerSpecFilePermission",
Title: "API server pod specification file permissions",
NodeType: "master",
Audit: "stat -c %a $apiserver.confs",
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GetNodesCommands(tt.commands, nil, "worker", "k8s-cis-1.23.2")
assert.NoError(t, err)
assert.True(t, reflect.DeepEqual(got, tt.want))
})
}
}
2 changes: 1 addition & 1 deletion pkg/collector/config/specs/k8s-cis-1.23.0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
version: "1.23.0"
name: k8s-cis
title: Node Specification for info collector
collectors:
commands:
- key: kubeAPIServerSpecFilePermission
title: API server pod specification file permissions
nodeType: master
Expand Down
74 changes: 52 additions & 22 deletions pkg/collector/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package collector

import (
"embed"
"encoding/base64"
"fmt"
"strings"

Expand Down Expand Up @@ -49,20 +50,43 @@ func LoadConfig(configMap map[string]string) (map[string]*SpecInfo, error) {
}

// LoadConfigParams load audit params data
func LoadConfigParams() (*Config, error) {
fullPath := fmt.Sprintf("%s/%s", configFolder, "config.yaml")
fContent, err := params.ReadFile(fullPath)
if err != nil {
return nil, err
func LoadConfigParams(nodeFileconfig, specVersionMapping string) (*Config, *Mapper, error) {
var decodedNodeFileconfig, decodedspecVersionMapping []byte
var err error
if nodeFileconfig != "" && specVersionMapping != "" {
decodedNodeFileconfig, err = base64.StdEncoding.DecodeString(nodeFileconfig)
if err != nil {
return nil, nil, err
}
decodedspecVersionMapping, err = base64.StdEncoding.DecodeString(specVersionMapping)
if err != nil {
return nil, nil, err
}
} else {
fullPath := fmt.Sprintf("%s/%s", configFolder, "config.yaml")
decodedNodeFileconfig, err = params.ReadFile(fullPath)
if err != nil {
return nil, nil, err
}
decodedspecVersionMapping = decodedNodeFileconfig
}
return getNodeParams(string(fContent))
return getNodeParams(string(decodedNodeFileconfig), string(decodedspecVersionMapping))
}

func LoadKubeletMapping() (map[string]string, error) {
fullPath := fmt.Sprintf("%s/%s", configFolder, "kubeletconfig-mapping.yaml")
fContent, err := params.ReadFile(fullPath)
if err != nil {
return nil, err
func LoadKubeletMapping(kubletConfigMapping string) (map[string]string, error) {
var fContent []byte
var err error
if len(kubletConfigMapping) > 0 {
fContent, err = base64.StdEncoding.DecodeString(kubletConfigMapping)
if err != nil {
return nil, err
}
} else {
fullPath := fmt.Sprintf("%s/%s", configFolder, "kubeletconfig-mapping.yaml")
fContent, err = params.ReadFile(fullPath)
if err != nil {
return nil, err
}
}
mapping := make(map[string]string)
err = yaml.Unmarshal(fContent, &mapping)
Expand All @@ -74,14 +98,14 @@ func LoadKubeletMapping() (map[string]string, error) {

// SpecInfo spec info with require comand to collect
type SpecInfo struct {
Version string `yaml:"version"`
Name string `yaml:"name"`
Title string `yaml:"title"`
Collectors []Collector `yaml:"collectors"`
Version string `yaml:"version"`
Name string `yaml:"name"`
Title string `yaml:"title"`
Commands []Command `yaml:"commands"`
}

// Collector details of info to collect
type Collector struct {
type Command struct {
Key string `yaml:"key"`
Title string `yaml:"title"`
Audit string `yaml:"audit"`
Expand All @@ -97,13 +121,18 @@ func getSpecInfo(info string) (*SpecInfo, error) {
return &specInfo, nil
}

func getNodeParams(info string) (*Config, error) {
func getNodeParams(config string, mapping string) (*Config, *Mapper, error) {
var np Config
err := yaml.Unmarshal([]byte(info), &np)
err := yaml.Unmarshal([]byte(config), &np)
if err != nil {
return nil, err
return nil, nil, err
}
var mp Mapper
err = yaml.Unmarshal([]byte(mapping), &mp)
if err != nil {
return nil, nil, err
}
return &np, nil
return &np, &mp, nil
}

// Node output node data with info results
Expand All @@ -121,10 +150,11 @@ type Info struct {
}

type Config struct {
Node NodeParams `yaml:"node"`
Node NodeParams `yaml:"node"`
}
type Mapper struct {
VersionMapping map[string][]SpecVersion `yaml:"version_mapping"`
}

type SpecVersion struct {
Name string
Version string `yaml:"cluster_version"`
Expand Down
6 changes: 5 additions & 1 deletion pkg/command/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ func init() {
rootCmd.PersistentFlags().StringP("spec-version", "v", "", "spec version. example 1.23.0")
rootCmd.PersistentFlags().StringP("cluster-version", "c", "", "cluser version. example 1.23.0")
rootCmd.PersistentFlags().StringP("node", "n", "", "node name")
rootCmd.PersistentFlags().StringP("kubelet-config", "", "", "kubelet config via api /api/v1/nodes/<>/proxy/configz encoded in base64")
rootCmd.PersistentFlags().StringP("kubelet-config", "", "", "kubelet config via api /api/v1/nodes/<>/proxy/configz encoded to base64")
rootCmd.PersistentFlags().StringP("spec-version-mapping", "", "", "k8s spec-version mapping encoded to base64")
rootCmd.PersistentFlags().StringP("node-config", "", "", "k8s node file config encoded to base64")
rootCmd.PersistentFlags().StringP("node-commands", "", "", "k8s node commands to be executed encoded to base64")
rootCmd.PersistentFlags().StringP("kubelet-config-mapping", "", "", "kubelet config api mapping encoded to base64")
}

var rootCmd = &cobra.Command{
Expand Down

0 comments on commit 74a24dd

Please sign in to comment.