Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support config and spec version flags #130

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading