Skip to content

Commit 1078598

Browse files
author
Andrew Reed
authored
Merge pull request #415 from areed/areed/weave-analyzer
Weave report analyzers
2 parents 1b65d1a + 91eb94b commit 1078598

File tree

6 files changed

+426
-0
lines changed

6 files changed

+426
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
apiVersion: troubleshoot.sh/v1beta2
2+
kind: SupportBundle
3+
metadata:
4+
name: collector-sample
5+
spec:
6+
collectors:
7+
- exec:
8+
collectorName: weave-report
9+
command:
10+
- /home/weave/weave
11+
args:
12+
- --local
13+
- report
14+
containerName: weave
15+
exclude: ""
16+
name: kots/kurl/weave
17+
namespace: kube-system
18+
selector:
19+
- name=weave-net
20+
timeout: 10s
21+
22+
analyzers:
23+
- weaveReport:
24+
reportFileGlob: kots/kurl/weave/kube-system/*/weave-report-stdout.txt

pkg/analyze/analyzer.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,5 +339,20 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
339339
return []*AnalyzeResult{result}, nil
340340
}
341341

342+
if analyzer.WeaveReport != nil {
343+
isExcluded, err := isExcluded(analyzer.WeaveReport.Exclude)
344+
if err != nil {
345+
return nil, err
346+
}
347+
if isExcluded {
348+
return nil, nil
349+
}
350+
results, err := analyzeWeaveReport(analyzer.WeaveReport, findFiles)
351+
if err != nil {
352+
return nil, err
353+
}
354+
return results, nil
355+
}
356+
342357
return nil, errors.New("invalid analyzer")
343358
}

pkg/analyze/weave.go

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
package analyzer
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"regexp"
7+
"strings"
8+
9+
"github.com/pkg/errors"
10+
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
11+
)
12+
13+
// relevant fields from https://github.com/weaveworks/weave/blob/e3712152d2a0fe3bc998964c948e45bdf8ff6144/prog/weaver/http.go#L295
14+
type WeaveReport struct {
15+
Router WeaveRouter
16+
IPAM WeaveIPAM
17+
}
18+
19+
type WeaveRouter struct {
20+
NickName string // this is the hostname
21+
Connections []WeaveConnection
22+
}
23+
24+
type WeaveIPAM struct {
25+
RangeNumIPs int
26+
ActiveIPs int
27+
PendingAllocates []string
28+
}
29+
30+
type WeaveConnection struct {
31+
State string
32+
Info string
33+
Attrs WeaveAttributes
34+
}
35+
36+
type WeaveAttributes struct {
37+
Encrypted bool `json:"encrypted"`
38+
MTU int `json:"mtu"`
39+
Name string `json:"name"`
40+
}
41+
42+
func analyzeWeaveReport(analyzer *troubleshootv1beta2.WeaveReportAnalyze, findFiles func(string) (map[string][]byte, error)) ([]*AnalyzeResult, error) {
43+
files, err := findFiles(analyzer.ReportFileGlob)
44+
if err != nil {
45+
return nil, errors.Wrapf(err, "failed to find weave report files in %q", analyzer.ReportFileGlob)
46+
}
47+
48+
if len(files) == 0 {
49+
return nil, nil
50+
}
51+
52+
reports := map[string]WeaveReport{}
53+
54+
for name, file := range files {
55+
report := WeaveReport{}
56+
57+
if err := json.Unmarshal(file, &report); err != nil {
58+
return nil, errors.Wrapf(err, "failed to unmarshal weave report json from %s", name)
59+
}
60+
61+
reports[report.Router.NickName] = report
62+
}
63+
64+
results := []*AnalyzeResult{}
65+
66+
if result := analyzeWeaveIPAMPools(reports); result != nil {
67+
results = append(results, result)
68+
}
69+
70+
if result := analyzeWeavePendingAllocation(reports); result != nil {
71+
results = append(results, result)
72+
}
73+
74+
if result := analyzeWeaveConnections(reports); result != nil {
75+
results = append(results, result)
76+
}
77+
78+
if len(results) == 0 {
79+
results = append(results, &AnalyzeResult{
80+
Title: "Weave Report",
81+
IsPass: true,
82+
Message: "No issues detected in weave report",
83+
})
84+
}
85+
86+
return results, nil
87+
}
88+
89+
func analyzeWeaveIPAMPools(reports map[string]WeaveReport) *AnalyzeResult {
90+
for _, report := range reports {
91+
if result := analyzeWeaveIPAMPool(&report); result != nil {
92+
return result
93+
}
94+
}
95+
96+
return nil
97+
}
98+
99+
func analyzeWeaveIPAMPool(report *WeaveReport) *AnalyzeResult {
100+
if report.IPAM.RangeNumIPs == 0 {
101+
return nil
102+
}
103+
104+
ipsUsed := float64(report.IPAM.ActiveIPs) / float64(report.IPAM.RangeNumIPs)
105+
if ipsUsed < 0.85 {
106+
return nil
107+
}
108+
109+
return &AnalyzeResult{
110+
Title: "Available Pod IPs",
111+
IsWarn: true,
112+
Message: fmt.Sprintf("%d of %d total available IPs have been assigned", report.IPAM.ActiveIPs, report.IPAM.RangeNumIPs),
113+
}
114+
}
115+
116+
func analyzeWeavePendingAllocation(reports map[string]WeaveReport) *AnalyzeResult {
117+
for _, report := range reports {
118+
if len(report.IPAM.PendingAllocates) > 0 {
119+
return &AnalyzeResult{
120+
Title: "Pending IP Allocation",
121+
IsWarn: true,
122+
Message: "Waiting for IPs to become available",
123+
}
124+
}
125+
}
126+
127+
return nil
128+
}
129+
130+
// Get the peer hostname for logging purposes from a string like: "encrypted fastdp 1a:5b:a9:53:2b:11(areed-aka-kkz0)"
131+
var weaveConnectionInfoPeerRegex = regexp.MustCompile(`\(([^)]+)\)$`)
132+
133+
func parseWeaveConnectionInfoHostname(info string) string {
134+
matches := weaveConnectionInfoPeerRegex.FindStringSubmatch(info)
135+
if len(matches) == 2 {
136+
return matches[1]
137+
}
138+
return ""
139+
}
140+
141+
func analyzeWeaveConnections(reports map[string]WeaveReport) *AnalyzeResult {
142+
for host, report := range reports {
143+
for _, connection := range report.Router.Connections {
144+
// older versions of weave show connection to self as failed
145+
if strings.HasPrefix(connection.Info, "cannot connect to ourself") {
146+
continue
147+
}
148+
149+
peer := parseWeaveConnectionInfoHostname(connection.Info)
150+
if peer == "" {
151+
peer = "peer"
152+
}
153+
154+
if connection.State != "established" {
155+
return &AnalyzeResult{
156+
Title: "Weave Inter-Node Connections",
157+
IsWarn: true,
158+
Message: fmt.Sprintf("Connection from %s to %s is %s", host, peer, connection.State),
159+
}
160+
}
161+
162+
if connection.Attrs.Name != "" && connection.Attrs.Name != "fastdp" {
163+
return &AnalyzeResult{
164+
Title: "Weave Inter-Node Connections",
165+
IsWarn: true,
166+
Message: fmt.Sprintf("Connection from %s to %s protocol is %q, not fastdp", host, peer, connection.Attrs.Name),
167+
}
168+
}
169+
}
170+
}
171+
172+
return nil
173+
}

0 commit comments

Comments
 (0)