Skip to content

Commit 2bf19ea

Browse files
authored
Ceph collectors and analyzers (#295)
* Ceph collectors and analyzers * updating based on prior pr * fixes * fixes
1 parent fd6af65 commit 2bf19ea

File tree

10 files changed

+642
-0
lines changed

10 files changed

+642
-0
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,5 @@ require (
5151
k8s.io/cli-runtime v0.18.0
5252
k8s.io/client-go v0.18.2
5353
sigs.k8s.io/controller-runtime v0.5.1-0.20200402191424-df180accb901
54+
sigs.k8s.io/controller-tools v0.3.0 // indirect
5455
)

go.sum

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ github.com/go-redis/redis/v7 v7.2.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRf
191191
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
192192
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
193193
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
194+
github.com/gobuffalo/flect v0.2.0 h1:EWCvMGGxOjsgwlWaP+f4+Hh6yrrte7JeFL2S6b+0hdM=
195+
github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
194196
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
195197
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
196198
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -325,6 +327,7 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7
325327
github.com/manifoldco/promptui v0.3.2 h1:rir7oByTERac6jhpHUPErHuopoRDvO3jxS+FdadEns8=
326328
github.com/manifoldco/promptui v0.3.2/go.mod h1:8JU+igZ+eeiiRku4T5BjtKh2ms8sziGpSYl1gN8Bazw=
327329
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
330+
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
328331
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
329332
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
330333
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
@@ -688,6 +691,8 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
688691
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
689692
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
690693
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
694+
gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966 h1:B0J02caTR6tpSJozBJyiAzT6CtBzjclw4pgm9gg8Ys0=
695+
gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
691696
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
692697
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
693698
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -732,6 +737,8 @@ k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl
732737
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0=
733738
sigs.k8s.io/controller-runtime v0.5.1-0.20200402191424-df180accb901 h1:qwHvTyQQBjATQeKPdJ0TwcXdtScjyI6GuiAQ5CSqEvM=
734739
sigs.k8s.io/controller-runtime v0.5.1-0.20200402191424-df180accb901/go.mod h1:j4echH3Y/UPHRpXS65rxGXujda8iWOheMQvDh1uNgaY=
740+
sigs.k8s.io/controller-tools v0.3.0 h1:y3YD99XOyWaXkiF1kd41uRvfp/64teWcrEZFuHxPhJ4=
741+
sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI=
735742
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
736743
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
737744
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=

pkg/analyze/analyzer.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,20 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
251251
}
252252
return []*AnalyzeResult{result}, nil
253253
}
254+
if analyzer.CephStatus != nil {
255+
isExcluded, err := isExcluded(analyzer.CephStatus.Exclude)
256+
if err != nil {
257+
return nil, err
258+
}
259+
if isExcluded {
260+
return nil, nil
261+
}
262+
result, err := cephStatus(analyzer.CephStatus, getFile)
263+
if err != nil {
264+
return nil, err
265+
}
266+
return []*AnalyzeResult{result}, nil
267+
}
254268
return nil, errors.New("invalid analyzer")
255269

256270
}

pkg/analyze/ceph.go

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package analyzer
2+
3+
import (
4+
"encoding/json"
5+
"path"
6+
"strings"
7+
8+
"github.com/pkg/errors"
9+
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
10+
"github.com/replicatedhq/troubleshoot/pkg/collect"
11+
)
12+
13+
type CephHealth string
14+
15+
const (
16+
CephHealthOK CephHealth = "HEALTH_OK"
17+
CephHealthWarn CephHealth = "HEALTH_WARN"
18+
CephHealthErr CephHealth = "HEALTH_ERR"
19+
)
20+
21+
func (a CephHealth) Compare(b CephHealth) int {
22+
if a == b {
23+
return 0
24+
}
25+
switch a {
26+
case CephHealthOK:
27+
return 1
28+
case CephHealthWarn:
29+
switch b {
30+
case CephHealthOK:
31+
return -1
32+
case CephHealthErr:
33+
return 1
34+
}
35+
return 1
36+
case CephHealthErr:
37+
switch b {
38+
case CephHealthOK, CephHealthWarn:
39+
return -1
40+
}
41+
return 1
42+
default:
43+
return -1
44+
}
45+
}
46+
47+
var CephStatusDefaultOutcomes = []*troubleshootv1beta2.Outcome{
48+
{
49+
Pass: &troubleshootv1beta2.SingleOutcome{
50+
Message: "Ceph is healthy",
51+
},
52+
},
53+
{
54+
Warn: &troubleshootv1beta2.SingleOutcome{
55+
Message: "Ceph status is HEALTH_WARN",
56+
URI: "https://rook.io/docs/rook/v1.4/ceph-common-issues.html",
57+
},
58+
},
59+
{
60+
Fail: &troubleshootv1beta2.SingleOutcome{
61+
Message: "Ceph status is HEALTH_ERR",
62+
URI: "https://rook.io/docs/rook/v1.4/ceph-common-issues.html",
63+
},
64+
},
65+
}
66+
67+
func cephStatus(analyzer *troubleshootv1beta2.CephStatusAnalyze, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
68+
fileName := path.Join(collect.GetCephCollectorFilepath(analyzer.CollectorName, analyzer.Namespace), "status.json")
69+
collected, err := getCollectedFileContents(fileName)
70+
if err != nil {
71+
return nil, errors.Wrap(err, "failed to read collected ceph status")
72+
}
73+
74+
title := analyzer.CheckName
75+
if title == "" {
76+
title = "Ceph Status"
77+
}
78+
79+
analyzeResult := &AnalyzeResult{
80+
Title: title,
81+
IconKey: "rook", // maybe this should be ceph?
82+
IconURI: "https://troubleshoot.sh/images/analyzer-icons/rook.svg?w=11&h=16",
83+
}
84+
85+
status := struct {
86+
Health struct {
87+
Status string `json:"status"`
88+
} `json:"health"`
89+
}{}
90+
if err := json.Unmarshal(collected, &status); err != nil {
91+
return nil, errors.Wrap(err, "failed to unmarshal status.json")
92+
}
93+
94+
if len(analyzer.Outcomes) == 0 {
95+
analyzer.Outcomes = CephStatusDefaultOutcomes
96+
}
97+
98+
for _, outcome := range analyzer.Outcomes {
99+
if outcome.Fail != nil {
100+
if outcome.Fail.When == "" {
101+
outcome.Fail.When = string(CephHealthErr)
102+
}
103+
match, err := compareCephStatus(status.Health.Status, outcome.Fail.When)
104+
if err != nil {
105+
return nil, errors.Wrap(err, "failed to compare ceph status")
106+
} else if match {
107+
analyzeResult.IsFail = true
108+
analyzeResult.Message = outcome.Fail.Message
109+
analyzeResult.URI = outcome.Fail.URI
110+
return analyzeResult, nil
111+
}
112+
} else if outcome.Warn != nil {
113+
if outcome.Warn.When == "" {
114+
outcome.Warn.When = string(CephHealthWarn)
115+
}
116+
match, err := compareCephStatus(status.Health.Status, outcome.Warn.When)
117+
if err != nil {
118+
return nil, errors.Wrap(err, "failed to compare ceph status")
119+
} else if match {
120+
analyzeResult.IsWarn = true
121+
analyzeResult.Message = outcome.Warn.Message
122+
analyzeResult.URI = outcome.Warn.URI
123+
return analyzeResult, nil
124+
}
125+
} else if outcome.Pass != nil {
126+
if outcome.Pass.When == "" {
127+
outcome.Pass.When = string(CephHealthOK)
128+
}
129+
match, err := compareCephStatus(status.Health.Status, outcome.Pass.When)
130+
if err != nil {
131+
return nil, errors.Wrap(err, "failed to compare ceph status")
132+
} else if match {
133+
analyzeResult.IsPass = true
134+
analyzeResult.Message = outcome.Pass.Message
135+
analyzeResult.URI = outcome.Pass.URI
136+
return analyzeResult, nil
137+
}
138+
}
139+
}
140+
141+
return analyzeResult, nil
142+
}
143+
144+
func compareCephStatus(actual, when string) (bool, error) {
145+
parts := strings.Split(strings.TrimSpace(when), " ")
146+
147+
if len(parts) == 1 {
148+
value := strings.TrimSpace(parts[0])
149+
return value == actual, nil
150+
}
151+
152+
if len(parts) != 2 {
153+
return false, errors.New("unable to parse when range")
154+
}
155+
156+
operator := strings.TrimSpace(parts[0])
157+
value := strings.TrimSpace(parts[1])
158+
159+
compareResult := CephHealth(actual).Compare(CephHealth(value))
160+
161+
switch operator {
162+
case "=", "==", "===":
163+
return compareResult == 0, nil
164+
case "<":
165+
return compareResult == -1, nil
166+
case ">":
167+
return compareResult == 1, nil
168+
case "<=":
169+
return compareResult <= 0, nil
170+
case ">=":
171+
return compareResult >= 0, nil
172+
default:
173+
return false, errors.New("unknown operator")
174+
}
175+
}

0 commit comments

Comments
 (0)