Skip to content

Commit b4b4697

Browse files
authored
Merge pull request #27 from Esonhugh/feat/kube-metrics
Feat/kube metrics
2 parents d3e9e6c + dae0d7c commit b4b4697

File tree

14 files changed

+603
-14
lines changed

14 files changed

+603
-14
lines changed

.github/workflows/build.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ jobs:
2222
with:
2323
go-version: ${{ env.GO_VERSION }}
2424

25+
- name: Install UPX
26+
uses: crazy-max/ghaction-upx@v3
27+
with:
28+
install-only: true
29+
2530
- name: Run GoReleaser
2631
uses: goreleaser/goreleaser-action@v3
2732
with:

.goreleaser.yaml

+9-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ project_name: k8spider
33
before:
44
hooks:
55
- go mod tidy
6-
- go generate ./...
76
builds:
87
- env:
98
- CGO_ENABLED=0
9+
ldflags:
10+
- -s -w
1011
goos:
1112
- darwin
1213
- windows
@@ -23,6 +24,13 @@ archives:
2324
- goos: windows
2425
format: zip
2526

27+
upx:
28+
- enabled: true
29+
compress: best
30+
brute: true
31+
lzma: true
32+
33+
2634
checksum:
2735
name_template: "checksums.txt"
2836
snapshot:

Makefile

+6-2
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@ BUILD_DIR = bin
33

44
MAIN_PROGRAM_NAME = k8spider
55

6-
default: build build-static
6+
default: build build-static check-size
77

88
# build
99
build:
1010
go build -o $(BUILD_DIR)/$(MAIN_PROGRAM_NAME) main.go
1111

1212
build-static:
1313
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o $(BUILD_DIR)/$(MAIN_PROGRAM_NAME)-linux-static main.go
14-
upx $(BUILD_DIR)/$(MAIN_PROGRAM_NAME)-linux-static
14+
upx --lzma --brute $(BUILD_DIR)/$(MAIN_PROGRAM_NAME)-linux-static
15+
16+
check-size:
17+
ls -alh $(BUILD_DIR)/$(MAIN_PROGRAM_NAME)*
18+
1519
clean:
1620
rm -rf $(BUILD_DIR)

cmd/all/all.go

+5
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,15 @@ var AllCmd = &cobra.Command{
4848
log.Warnf("ParseStringToIPNet failed: %v", err)
4949
return
5050
}
51+
5152
var finalRecord define.Records
5253
if command.Opts.MultiThreadingMode {
5354
finalRecord = RunMultiThread(ipNets, command.Opts.ThreadingNum)
5455
} else {
5556
finalRecord = Run(ipNets)
5657
}
5758
printer.PrintResult(finalRecord, command.Opts.OutputFile)
59+
5860
PostRun(finalRecord)
5961
},
6062
}
@@ -78,6 +80,9 @@ func RunMultiThread(net *net.IPNet, count int) (finalRecord define.Records) {
7880
}
7981

8082
func PostRun(finalRecord define.Records) {
83+
if finalRecord == nil || len(finalRecord) == 0 {
84+
return
85+
}
8186
log.Info("Extract Namespaces: ")
8287
list := post.RecordsDumpNameSpace(finalRecord, command.Opts.Zone)
8388
for _, ns := range list {

cmd/dnsutils/dns.go

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package dnsutils
2+
3+
import (
4+
"strings"
5+
6+
command "github.com/esonhugh/k8spider/cmd"
7+
"github.com/esonhugh/k8spider/pkg"
8+
log "github.com/sirupsen/logrus"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
var queryType string
13+
14+
func init() {
15+
DNSCmd.PersistentFlags().StringVarP(&queryType, "type", "t", "A", "query type")
16+
command.RootCmd.AddCommand(DNSCmd)
17+
}
18+
19+
var DNSCmd = &cobra.Command{
20+
Use: "dns",
21+
Aliases: []string{"dig"},
22+
Short: "dns is a command to query dns server",
23+
Run: func(cmd *cobra.Command, args []string) {
24+
var querier pkg.DnsQuery
25+
switch strings.ToLower(queryType) {
26+
case "a", "aaaa":
27+
querier = pkg.QueryA
28+
case "ptr":
29+
querier = pkg.QueryPTR
30+
case "srv":
31+
querier = pkg.QuerySRV
32+
case "txt":
33+
querier = pkg.QueryTXT
34+
default:
35+
querier = pkg.QueryA
36+
}
37+
for _, query := range args {
38+
res, err := querier(query)
39+
if err != nil {
40+
log.Warnf("Query %s failed: %v", query, err)
41+
continue
42+
}
43+
log.Infof("Query [%d] %s: %v", queryType, query, res)
44+
}
45+
},
46+
}

cmd/metrics/parser.go

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package metrics
2+
3+
import (
4+
"bufio"
5+
"io"
6+
"net/http"
7+
"os"
8+
"strings"
9+
10+
cmdx "github.com/esonhugh/k8spider/cmd"
11+
"github.com/esonhugh/k8spider/pkg/metrics"
12+
log "github.com/sirupsen/logrus"
13+
"github.com/spf13/cobra"
14+
)
15+
16+
var MetricOpt struct {
17+
From string
18+
}
19+
20+
func init() {
21+
cmdx.RootCmd.AddCommand(MetricCmd)
22+
MetricCmd.PersistentFlags().StringVarP(&MetricOpt.From, "metric", "m", "", "metrics from (file / remote url)")
23+
24+
}
25+
26+
var MetricCmd = &cobra.Command{
27+
Use: "metric",
28+
Short: "parse kube stat metrics to readable resource",
29+
Run: func(cmd *cobra.Command, args []string) {
30+
if MetricOpt.From == "" {
31+
return
32+
}
33+
log.Debugf("parse metrics from %v", MetricOpt.From)
34+
rule := metrics.DefaultMatchRules()
35+
if err := rule.Compile(); err != nil {
36+
log.Fatalf("compile rule failed: %v", err)
37+
}
38+
log.Debugf("compiled rules completed, start to get resource \n")
39+
40+
ot := output()
41+
42+
var r io.Reader
43+
if strings.HasPrefix("http://", MetricOpt.From) || strings.HasPrefix("https://", MetricOpt.From) {
44+
resp, err := http.Get(MetricOpt.From)
45+
if err != nil {
46+
log.Fatalf("get metrics from %v failed: %v", MetricOpt.From, err)
47+
}
48+
defer resp.Body.Close()
49+
r = resp.Body
50+
} else {
51+
f, err := os.OpenFile(MetricOpt.From, os.O_RDONLY, 0666)
52+
if err != nil {
53+
log.Fatalf("open file %v failed: %v", MetricOpt.From, err)
54+
}
55+
defer f.Close()
56+
r = f
57+
}
58+
log.Debugf("start to parse metrics line by line\n")
59+
60+
var rx []*metrics.MetricMatcher
61+
62+
scanner := bufio.NewScanner(r)
63+
for scanner.Scan() {
64+
line := scanner.Text()
65+
res, err := rule.Match(line)
66+
if err != nil {
67+
continue
68+
} else {
69+
log.Debugf("matched: %s", res.DumpString())
70+
rx = append(rx, res.CopyData())
71+
}
72+
}
73+
if err := scanner.Err(); err != nil {
74+
log.Warnf("scan metrics failed and break out, reason: %v", err)
75+
}
76+
var res metrics.ResourceList = metrics.ConvertToResource(rx)
77+
log.Debugf("parse metrics completed, start to print result\n")
78+
79+
res.Print(ot)
80+
},
81+
}
82+
83+
func output() io.WriteCloser {
84+
if cmdx.Opts.OutputFile != "" {
85+
f, err := os.OpenFile(cmdx.Opts.OutputFile, os.O_CREATE|os.O_WRONLY, 0644)
86+
if err != nil {
87+
log.Warnf("create output file failed: %v", err)
88+
return nil
89+
}
90+
return f
91+
} else {
92+
return os.Stdout
93+
}
94+
}

go.mod

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
module github.com/esonhugh/k8spider
22

3-
go 1.19
3+
go 1.21.0
4+
5+
toolchain go1.23.2
46

57
require (
8+
github.com/elastic/go-grok v0.3.1
69
github.com/miekg/dns v1.1.58
710
github.com/sirupsen/logrus v1.9.0
811
github.com/spf13/cobra v1.5.0
912
)
1013

1114
require (
1215
github.com/inconshreveable/mousetrap v1.0.0 // indirect
16+
github.com/magefile/mage v1.15.0 // indirect
1317
github.com/spf13/pflag v1.0.5 // indirect
14-
github.com/stretchr/testify v1.8.0 // indirect
15-
golang.org/x/mod v0.14.0 // indirect
18+
golang.org/x/mod v0.17.0 // indirect
1619
golang.org/x/net v0.20.0 // indirect
1720
golang.org/x/sys v0.16.0 // indirect
1821
golang.org/x/tools v0.17.0 // indirect

go.sum

+10-7
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
22
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
33
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
44
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/elastic/go-grok v0.3.1 h1:WEhUxe2KrwycMnlvMimJXvzRa7DoByJB4PVUIE1ZD/U=
6+
github.com/elastic/go-grok v0.3.1/go.mod h1:n38ls8ZgOboZRgKcjMY8eFeZFMmcL9n2lP0iHhIDk64=
57
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
68
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
9+
github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
10+
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
711
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
812
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
913
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -16,16 +20,15 @@ github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJ
1620
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
1721
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
1822
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
19-
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
2023
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
21-
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
22-
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
23-
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
24-
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
25-
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
24+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
25+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
26+
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
27+
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
2628
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
2729
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
28-
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
30+
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
31+
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
2932
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
3033
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
3134
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

main.go

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"github.com/esonhugh/k8spider/cmd"
55
_ "github.com/esonhugh/k8spider/cmd/all"
66
_ "github.com/esonhugh/k8spider/cmd/axfr"
7+
_ "github.com/esonhugh/k8spider/cmd/dnsutils"
8+
_ "github.com/esonhugh/k8spider/cmd/metrics"
79
_ "github.com/esonhugh/k8spider/cmd/neighbor"
810
_ "github.com/esonhugh/k8spider/cmd/service"
911
_ "github.com/esonhugh/k8spider/cmd/subnet"

pkg/metrics/matcher.go

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package metrics
2+
3+
import "errors"
4+
5+
type MatchRules []*MetricMatcher
6+
7+
func GenerateMatchRules() MatchRules {
8+
return make(MatchRules, 0)
9+
}
10+
11+
func DefaultMatchRules() MatchRules {
12+
return []*MetricMatcher{
13+
NewMetricMatcher("configmap").AddLabel("namespace").AddLabel("configmap"),
14+
NewMetricMatcher("secret").AddLabel("namespace").AddLabel("secret"),
15+
16+
NewMetricMatcher("node").AddLabel("node").AddLabel("kernel_version").
17+
AddLabel("os_image").AddLabel("container_runtime_version").
18+
AddLabel("provider_id").AddLabel("internal_ip"),
19+
20+
NewMetricMatcher("pod").AddLabel("namespace").AddLabel("pod").AddLabel("node").
21+
AddLabel("host_ip").AddLabel("pod_ip"),
22+
NewMetricMatcher("container").SetHeader("kube_pod_container_info").AddLabel("namespace").
23+
AddLabel("pod").AddLabel("container").AddLabel("image"),
24+
NewMetricMatcher("cronjob").AddLabel("namespace").AddLabel("cronjob").
25+
AddLabel("schedule"),
26+
27+
NewMetricMatcher("service_account").SetHeader("kube_pod_service_account").
28+
AddLabel("namespace").AddLabel("pod").AddLabel("service_account"),
29+
30+
NewMetricMatcher("service").AddLabel("namespace").AddLabel("service").
31+
AddLabel("cluster_ip").AddLabel("external_name").AddLabel("load_balancer_ip"),
32+
NewMetricMatcher("endpoint_address").SetHeader("kube_endpoint_address").
33+
AddLabel("namespace").AddLabel("endpoint").AddLabel("ip"),
34+
NewMetricMatcher("endpoint_port").SetHeader("kube_endpoint_ports").
35+
AddLabel("namespace").AddLabel("endpoint").AddLabel("port_number"),
36+
}
37+
}
38+
39+
func (m MatchRules) Compile() error {
40+
var err error = nil
41+
for i := range m {
42+
e := m[i].Compile()
43+
if e != nil {
44+
err = errors.Join(err, e)
45+
}
46+
}
47+
return err
48+
}
49+
50+
func (m MatchRules) Match(target string) (*MetricMatcher, error) {
51+
for _, r := range m {
52+
_, e := r.Match(target)
53+
if e != nil {
54+
continue
55+
} else {
56+
return r, nil
57+
}
58+
}
59+
return nil, errors.New("no match found")
60+
}

0 commit comments

Comments
 (0)