Skip to content

Commit 91eb94b

Browse files
author
Andrew Reed
committed
Weave report analyzers
The IPAM pool analyzer checks that utilization of the pod IP subnet is less than 85%. For example, if using 10.32.0.0/12, this analyzer will warn if 3,482 IPs are currently allocated to pods. The pending allocation analyzer checks that the IPAM status in the report has no items for the PendingAllocates field. This indicates the IPAM service is not ready according to the code in the weave status template https://github.com/weaveworks/weave/blob/e3712152d2a0fe3bc998964c948e45bdf8ff6144/prog/weaver/http.go#L186. The weave connections analyzer checks that all connections to remote peers are in the established state. The state will be "pending" if UDP is blocked between nodes and will be "failed" if the weave pod on the remote node is in a crash loop. To force a pending state for testing, run the commands `iptables -A INPUT -p udp --dport 6784 -j REJECT` and `iptables -A INPUT -p udp --dport 6783 -j REJECT` on a peer. The weave connections analyzer also checks that all connections are using the fastdp protocol. A commopn issue seen in the field on CentOS/RHEL 7 is that some sides of a connection are using fastdp and other sides have fallen back to sleeve. Set the WEAVE_NO_FASTDP env var on the weave daemonset to "true" to test this analyzer.
1 parent 1b65d1a commit 91eb94b

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)