forked from Checkmarx/kics
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkuberneter.go
132 lines (105 loc) · 3.15 KB
/
kuberneter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
Package kuberneter implements calls to the Kubernetes API in order to scan the runtime information of the resources
*/
package kuberneter
import (
"context"
"os"
"path/filepath"
"strings"
"sync"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"k8s.io/apimachinery/pkg/api/meta"
"sigs.k8s.io/controller-runtime/pkg/client"
)
type k8sAPICall struct {
client client.Client
options *K8sAPIOptions
ctx *context.Context
destinationPath string
}
type supportedKinds map[string]map[string]interface{}
var getK8sClientFunc = getK8sClient // for testing purposes
// Import imports the k8s cluster resources into the destination using kuberneter path
func Import(ctx context.Context, kuberneterPath, destinationPath string) (string, error) {
log.Info().Msg("importing k8s cluster resources")
supportedKinds := buildSupportedKinds()
defer func() { supportedKinds = nil }()
// extract k8s API options
k8sAPIOptions, err := extractK8sAPIOptions(kuberneterPath, supportedKinds)
if err != nil {
return "", err
}
// get the k8s client
c, err := getK8sClientFunc()
if err != nil {
return "", err
}
// create folder to save k8s resources
destination, err := getDestinationFolder(destinationPath)
if err != nil {
return "", err
}
if c == nil {
return destination, errors.New("failed to get client")
}
info := &k8sAPICall{
client: c,
options: k8sAPIOptions,
ctx: &ctx,
destinationPath: destination,
}
// list and save k8s resources
for i := range k8sAPIOptions.Namespaces {
info.listK8sResources(i, supportedKinds)
}
return destination, nil
}
func (info *k8sAPICall) listK8sResources(idx int, supKinds *supportedKinds) {
var wg sync.WaitGroup
for apiVersion := range *supKinds {
kinds := (*supKinds)[apiVersion]
if isTarget(apiVersion, info.options.APIVersions) {
wg.Add(1)
go info.listKinds(apiVersion, kinds, info.options.Namespaces[idx], &wg)
}
}
wg.Wait()
}
func (info *k8sAPICall) listKinds(apiVersion string, kinds map[string]interface{}, namespace string, wg *sync.WaitGroup) {
defer wg.Done()
sb := &strings.Builder{}
apiVersionFolder := filepath.Join(info.destinationPath, apiVersion)
if err := os.MkdirAll(apiVersionFolder, os.ModePerm); err != nil {
log.Error().Msgf("unable to create folder %s: %s", apiVersionFolder, err)
return
}
for kind := range kinds {
kindList := kinds[kind]
if !isTarget(kind, info.options.Kinds) {
continue
}
if _, ok := kindList.(client.ObjectList); !ok {
continue
}
resource := kindList.(client.ObjectList)
err := info.client.List(*info.ctx, resource, client.InNamespace(namespace))
if err != nil {
log.Info().Msgf("failed to list %s: %s", apiVersion, err)
}
objList, err := meta.ExtractList(resource)
if err != nil {
log.Info().Msgf("failed to extract list: %s", err)
}
log.Info().Msgf("KICS found %d %s(s) in %s from %s", len(objList), kind, getNamespace(namespace), apiVersion)
for i := range objList {
item := objList[i]
sb = info.getResource(item, apiVersion, kind, sb)
}
if len(sb.String()) > 0 {
info.saveK8sResources(kind, sb.String(), apiVersionFolder)
}
sb.Reset()
}
}