mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-02-14 18:29:53 +00:00
feat: Allow templating of outcome messages for the JSON/YAML compare analyzers (#1432)
* feat: allow templating of the outcome message for the JSON and YAML Compare analyzers * Update pkg/analyze/json_compare.go Co-authored-by: Evans Mungai <evans@replicated.com>
This commit is contained in:
4
Makefile
4
Makefile
@@ -165,12 +165,8 @@ CONTROLLER_GEN=$(shell which controller-gen)
|
||||
|
||||
.PHONY: client-gen
|
||||
client-gen:
|
||||
ifeq (, $(shell which client-gen 2>/dev/null))
|
||||
go install k8s.io/code-generator/cmd/client-gen@v0.28.2
|
||||
CLIENT_GEN=$(shell go env GOPATH)/bin/client-gen
|
||||
else
|
||||
CLIENT_GEN=$(shell which client-gen)
|
||||
endif
|
||||
|
||||
.PHONY: release
|
||||
release: export GITHUB_TOKEN = $(shell echo ${GITHUB_TOKEN_TROUBLESHOOT})
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
@@ -82,3 +84,24 @@ func IsInCluster() bool {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// RenderTemplate renders a template and returns the result as a string
|
||||
func RenderTemplate(tpl string, data interface{}) (string, error) {
|
||||
// Create a new template and parse the letter into it
|
||||
t, err := template.New("data").Parse(tpl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Create a new buffer
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
// Execute the template and write the bytes to the buffer
|
||||
err = t.Execute(buf, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Return the string representation of the buffer
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
@@ -246,3 +246,59 @@ func TestAppend(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenderTemplate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tpl string
|
||||
data interface{}
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "empty template and data",
|
||||
tpl: "",
|
||||
data: nil,
|
||||
want: "",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty template with data",
|
||||
tpl: "",
|
||||
data: map[string]string{"Name": "World"},
|
||||
want: "",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty data with template with no keys",
|
||||
tpl: "Hello, World!",
|
||||
data: nil,
|
||||
want: "Hello, World!",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "simple template",
|
||||
tpl: "Hello, {{ .Name }}!",
|
||||
data: map[string]string{"Name": "World"},
|
||||
want: "Hello, World!",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "template with missing key",
|
||||
tpl: "Hello, {{ .Name }}!",
|
||||
data: map[string]string{"Name2": "World"},
|
||||
want: "Hello, <no value>!",
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := RenderTemplate(tt.tpl, tt.data)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("RenderTemplate() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
assert.Equal(t, tt.want, got, "RenderTemplate() = %v, want %v", got, tt.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
util "github.com/replicatedhq/troubleshoot/internal/util"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
iutils "github.com/replicatedhq/troubleshoot/pkg/interfaceutils"
|
||||
"k8s.io/client-go/util/jsonpath"
|
||||
@@ -54,6 +55,8 @@ func (a *AnalyzeJsonCompare) analyzeJsonCompare(analyzer *troubleshootv1beta2.Js
|
||||
return nil, errors.Wrap(err, "failed to parse collected data as json")
|
||||
}
|
||||
|
||||
originalActual := actual
|
||||
|
||||
if analyzer.Path != "" {
|
||||
actual, err = iutils.GetAtPath(actual, analyzer.Path)
|
||||
if err != nil {
|
||||
@@ -112,6 +115,11 @@ func (a *AnalyzeJsonCompare) analyzeJsonCompare(analyzer *troubleshootv1beta2.Js
|
||||
}
|
||||
}
|
||||
|
||||
outcome.Fail.Message, err = util.RenderTemplate(outcome.Fail.Message, originalActual)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to render template on outcome message")
|
||||
}
|
||||
|
||||
if when == equal {
|
||||
result.IsFail = true
|
||||
result.Message = outcome.Fail.Message
|
||||
@@ -128,6 +136,11 @@ func (a *AnalyzeJsonCompare) analyzeJsonCompare(analyzer *troubleshootv1beta2.Js
|
||||
}
|
||||
}
|
||||
|
||||
outcome.Warn.Message, err = util.RenderTemplate(outcome.Warn.Message, originalActual)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to render template on outcome message")
|
||||
}
|
||||
|
||||
if when == equal {
|
||||
result.IsWarn = true
|
||||
result.Message = outcome.Warn.Message
|
||||
@@ -144,6 +157,11 @@ func (a *AnalyzeJsonCompare) analyzeJsonCompare(analyzer *troubleshootv1beta2.Js
|
||||
}
|
||||
}
|
||||
|
||||
outcome.Pass.Message, err = util.RenderTemplate(outcome.Pass.Message, originalActual)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to render template on outcome message")
|
||||
}
|
||||
|
||||
if when == equal {
|
||||
result.IsPass = true
|
||||
result.Message = outcome.Pass.Message
|
||||
|
||||
@@ -756,6 +756,48 @@ func Test_jsonCompare(t *testing.T) {
|
||||
]
|
||||
}`),
|
||||
},
|
||||
{
|
||||
name: "basic comparison with outcome message templated",
|
||||
analyzer: troubleshootv1beta2.JsonCompare{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "Status: {{ .morestuff.status }}, Info: {{ .morestuff.info }}",
|
||||
When: "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "Status: {{ .morestuff.status }}, Info: {{ .morestuff.info }}",
|
||||
When: "false",
|
||||
},
|
||||
},
|
||||
},
|
||||
CollectorName: "json-compare",
|
||||
FileName: "json-compare.json",
|
||||
Path: "morestuff.status",
|
||||
Value: `"ready"`,
|
||||
},
|
||||
expectResult: AnalyzeResult{
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "json-compare",
|
||||
Message: "Status: notready, Info: morestuff is not ready",
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
},
|
||||
fileContents: []byte(`{
|
||||
"stuff": {
|
||||
"status": "ready",
|
||||
"info": "this stuff is ready"
|
||||
},
|
||||
"morestuff": {
|
||||
"status": "notready",
|
||||
"info": "morestuff is not ready"
|
||||
}
|
||||
}`),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
util "github.com/replicatedhq/troubleshoot/internal/util"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
iutils "github.com/replicatedhq/troubleshoot/pkg/interfaceutils"
|
||||
"gopkg.in/yaml.v2"
|
||||
@@ -50,6 +51,8 @@ func (a *AnalyzeYamlCompare) analyzeYamlCompare(analyzer *troubleshootv1beta2.Ya
|
||||
return nil, errors.Wrap(err, "failed to parse collected data as yaml doc")
|
||||
}
|
||||
|
||||
originalActual := actual
|
||||
|
||||
if analyzer.Path != "" {
|
||||
actual, err = iutils.GetAtPath(actual, analyzer.Path)
|
||||
if err != nil {
|
||||
@@ -81,6 +84,11 @@ func (a *AnalyzeYamlCompare) analyzeYamlCompare(analyzer *troubleshootv1beta2.Ya
|
||||
}
|
||||
}
|
||||
|
||||
outcome.Fail.Message, err = util.RenderTemplate(outcome.Fail.Message, originalActual)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to render template on outcome message")
|
||||
}
|
||||
|
||||
if when == equal {
|
||||
result.IsFail = true
|
||||
result.Message = outcome.Fail.Message
|
||||
@@ -96,6 +104,11 @@ func (a *AnalyzeYamlCompare) analyzeYamlCompare(analyzer *troubleshootv1beta2.Ya
|
||||
}
|
||||
}
|
||||
|
||||
outcome.Warn.Message, err = util.RenderTemplate(outcome.Warn.Message, originalActual)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to render template on outcome message")
|
||||
}
|
||||
|
||||
if when == equal {
|
||||
result.IsWarn = true
|
||||
result.Message = outcome.Warn.Message
|
||||
@@ -111,6 +124,11 @@ func (a *AnalyzeYamlCompare) analyzeYamlCompare(analyzer *troubleshootv1beta2.Ya
|
||||
}
|
||||
}
|
||||
|
||||
outcome.Pass.Message, err = util.RenderTemplate(outcome.Pass.Message, originalActual)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to render template on outcome message")
|
||||
}
|
||||
|
||||
if when == equal {
|
||||
result.IsPass = true
|
||||
result.Message = outcome.Pass.Message
|
||||
|
||||
@@ -430,6 +430,45 @@ otherstuff:
|
||||
},
|
||||
fileContents: []byte(``),
|
||||
},
|
||||
{
|
||||
name: "basic comparison with outcome message templated",
|
||||
analyzer: troubleshootv1beta2.YamlCompare{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "Status: {{ .stuff.status }}, Info: {{ .stuff.info }}",
|
||||
When: "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "Status: {{ .stuff.status }}, Info: {{ .stuff.info }}",
|
||||
When: "false",
|
||||
},
|
||||
},
|
||||
},
|
||||
CollectorName: "yaml-compare",
|
||||
FileName: "yaml-compare.yaml",
|
||||
Value: `ready`,
|
||||
Path: "stuff.status",
|
||||
},
|
||||
expectResult: AnalyzeResult{
|
||||
IsPass: true,
|
||||
IsWarn: false,
|
||||
IsFail: false,
|
||||
Title: "yaml-compare",
|
||||
Message: "Status: ready, Info: stuff is ready",
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
},
|
||||
fileContents: []byte(`
|
||||
stuff:
|
||||
status: ready
|
||||
info: stuff is ready
|
||||
morestuff:
|
||||
status: notready
|
||||
info: morestuff is not ready`),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
Reference in New Issue
Block a user