Skip to content

Commit

Permalink
update Loki payload and test cases
Browse files Browse the repository at this point in the history
Signed-off-by: Frank Jogeleit <[email protected]>
  • Loading branch information
fjogeleit committed Sep 18, 2024
1 parent ce79520 commit 67f85e4
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 128 deletions.
32 changes: 16 additions & 16 deletions pkg/target/loki/loki.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,27 @@ type Options struct {
Password string
}

type payload struct {
Streams []stream `json:"streams"`
type Payload struct {
Streams []Stream `json:"streams"`
}

type stream struct {
type Stream struct {
Stream map[string]string `json:"stream"`
Values []value `json:"values"`
Values []Value `json:"values"`
}

type value = []string
type Value = []string

func newLokiStream(result v1alpha2.PolicyReportResult, customFields map[string]string) stream {
func newLokiStream(result v1alpha2.PolicyReportResult, customFields map[string]string) Stream {
timestamp := time.Now()
if result.Timestamp.Seconds != 0 {
timestamp = time.Unix(result.Timestamp.Seconds, int64(result.Timestamp.Nanos))
}

labels := map[string]string{
"status": string(result.Result),
"policy": result.Policy,
"source": "policy-reporter",
"status": string(result.Result),
"policy": result.Policy,
"createdBy": "policy-reporter",
}

if result.Rule != "" {
Expand All @@ -59,7 +59,7 @@ func newLokiStream(result v1alpha2.PolicyReportResult, customFields map[string]s
labels["severity"] = string(result.Severity)
}
if result.Source != "" {
labels["producer"] = result.Source
labels["source"] = result.Source
}
if result.HasResource() {
res := result.GetResource()
Expand All @@ -84,8 +84,8 @@ func newLokiStream(result v1alpha2.PolicyReportResult, customFields map[string]s
labels[keyReplacer.Replace(label)] = labelReplacer.Replace(value)
}

return stream{
Values: []value{[]string{fmt.Sprintf("%v", timestamp.UnixNano()), "[" + strings.ToUpper(string(result.Severity)) + "] " + result.Message}},
return Stream{
Values: []Value{[]string{fmt.Sprintf("%v", timestamp.UnixNano()), "[" + strings.ToUpper(string(result.Severity)) + "] " + result.Message}},
Stream: labels,
}
}
Expand All @@ -101,20 +101,20 @@ type client struct {
}

func (l *client) Send(result v1alpha2.PolicyReportResult) {
l.send(payload{
Streams: []stream{
l.send(Payload{
Streams: []Stream{
newLokiStream(result, l.customFields),
},
})
}

func (l *client) BatchSend(_ v1alpha2.ReportInterface, results []v1alpha2.PolicyReportResult) {
l.send(payload{Streams: helper.Map(results, func(result v1alpha2.PolicyReportResult) stream {
l.send(Payload{Streams: helper.Map(results, func(result v1alpha2.PolicyReportResult) Stream {
return newLokiStream(result, l.customFields)
})})
}

func (l *client) send(payload payload) {
func (l *client) send(payload Payload) {
req, err := http.CreateJSONRequest("POST", l.host, payload)
if err != nil {
return
Expand Down
148 changes: 36 additions & 112 deletions pkg/target/loki/loki_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/kyverno/policy-reporter/pkg/fixtures"
"github.com/kyverno/policy-reporter/pkg/target"
"github.com/kyverno/policy-reporter/pkg/target/loki"
"github.com/stretchr/testify/assert"
)

type testClient struct {
Expand Down Expand Up @@ -39,7 +40,7 @@ func Test_LokiTarget(t *testing.T) {
t.Errorf("Unexpected Host: %s", agend)
}

if url := req.URL.String(); url != "http://localhost:3100/api/prom/push" {
if url := req.URL.String(); url != "http://localhost:3100/loki/api/v1/push" {
t.Errorf("Unexpected Host: %s", url)
}

Expand All @@ -48,55 +49,30 @@ func Test_LokiTarget(t *testing.T) {
}

expectedLine := fmt.Sprintf("[%s] %s", strings.ToUpper(string(fixtures.CompleteTargetSendResult.Severity)), fixtures.CompleteTargetSendResult.Message)
labels, line := convertAndValidateBody(req, t)
if line != expectedLine {
t.Errorf("Unexpected LineContent: %s", line)
}
if !strings.Contains(labels, "policy=\""+fixtures.CompleteTargetSendResult.Policy+"\"") {
t.Error("Missing Content for Label 'policy'")
}
if !strings.Contains(labels, "status=\""+string(fixtures.CompleteTargetSendResult.Result)+"\"") {
t.Error("Missing Content for Label 'status'")
}
if !strings.Contains(labels, "source=\"policy-reporter\"") {
t.Error("Missing Content for Label 'policy-reporter'")
}
if !strings.Contains(labels, "rule=\""+fixtures.CompleteTargetSendResult.Rule+"\"") {
t.Error("Missing Content for Label 'rule'")
}
if !strings.Contains(labels, "category=\""+fixtures.CompleteTargetSendResult.Category+"\"") {
t.Error("Missing Content for Label 'category'")
}
if !strings.Contains(labels, "severity=\""+string(fixtures.CompleteTargetSendResult.Severity)+"\"") {
t.Error("Missing Content for Label 'severity'")
}
if !strings.Contains(labels, "custom=\"label\"") {
t.Error("Missing Content for Label 'severity'")
}

stream := convertAndValidateBody(req, t)

assert.Equal(t, expectedLine, stream.Values[0][1])
assert.Equal(t, fixtures.CompleteTargetSendResult.Rule, stream.Stream["rule"])
assert.Equal(t, fixtures.CompleteTargetSendResult.Policy, stream.Stream["policy"])
assert.Equal(t, fixtures.CompleteTargetSendResult.Category, stream.Stream["category"])
assert.Equal(t, string(fixtures.CompleteTargetSendResult.Result), stream.Stream["result"])
assert.Equal(t, string(fixtures.CompleteTargetSendResult.Severity), stream.Stream["severity"])

res := fixtures.CompleteTargetSendResult.GetResource()
if !strings.Contains(labels, "kind=\""+res.Kind+"\"") {
t.Error("Missing Content for Label 'kind'")
}
if !strings.Contains(labels, "name=\""+res.Name+"\"") {
t.Error("Missing Content for Label 'name'")
}
if !strings.Contains(labels, "uid=\""+string(res.UID)+"\"") {
t.Error("Missing Content for Label 'uid'")
}
if !strings.Contains(labels, "namespace=\""+res.Namespace+"\"") {
t.Error("Missing Content for Label 'namespace'")
}
if !strings.Contains(labels, "version=\""+fixtures.CompleteTargetSendResult.Properties["version"]+"\"") {
t.Error("Missing Content for Label 'version'")
}
assert.Equal(t, res.Kind, stream.Stream["kind"])
assert.Equal(t, res.Name, stream.Stream["name"])
assert.Equal(t, string(res.UID), stream.Stream["uid"])
assert.Equal(t, res.Namespace, stream.Stream["namespace"])

assert.Equal(t, fixtures.CompleteTargetSendResult.Properties["version"], stream.Stream["version"])
}

client := loki.NewClient(loki.Options{
ClientOptions: target.ClientOptions{
Name: "Loki",
},
Host: "http://localhost:3100/api/prom/push",
Host: "http://localhost:3100/loki/api/v1/push",
CustomFields: map[string]string{"custom": "label"},
HTTPClient: testClient{callback, 200},
Username: "username",
Expand All @@ -116,52 +92,28 @@ func Test_LokiTarget(t *testing.T) {
t.Errorf("Unexpected Host: %s", agend)
}

if url := req.URL.String(); url != "http://localhost:3100/api/prom/push" {
if url := req.URL.String(); url != "http://localhost:3100/loki/api/v1/push" {
t.Errorf("Unexpected Host: %s", url)
}

expectedLine := fmt.Sprintf("[%s] %s", strings.ToUpper(string(fixtures.MinimalTargetSendResult.Severity)), fixtures.MinimalTargetSendResult.Message)
labels, line := convertAndValidateBody(req, t)
if line != expectedLine {
t.Errorf("Unexpected LineContent: %s", line)
}
if !strings.Contains(labels, "policy=\""+fixtures.MinimalTargetSendResult.Policy+"\"") {
t.Error("Missing Content for Label 'policy'")
}
if !strings.Contains(labels, "status=\""+string(fixtures.MinimalTargetSendResult.Result)+"\"") {
t.Error("Missing Content for Label 'status'")
}
if !strings.Contains(labels, "source=\"policy-reporter\"") {
t.Error("Missing Content for Label 'policy-reporter'")
}
if strings.Contains(labels, "rule") {
t.Error("Unexpected Label 'rule'")
}
if strings.Contains(labels, "category") {
t.Error("Unexpected Label 'category'")
}
if strings.Contains(labels, "severity") {
t.Error("Unexpected 'severity'")
}
if strings.Contains(labels, "kind") {
t.Error("Unexpected Label 'kind'")
}
if strings.Contains(labels, "name") {
t.Error("Unexpected 'name'")
}
if strings.Contains(labels, "uid") {
t.Error("Unexpected 'uid'")
}
if strings.Contains(labels, "namespace") {
t.Error("Unexpected 'namespace'")
}
stream := convertAndValidateBody(req, t)

assert.Equal(t, expectedLine, stream.Values[0][1])
assert.Equal(t, fixtures.MinimalTargetSendResult.Rule, stream.Stream["rule"])
assert.Equal(t, fixtures.MinimalTargetSendResult.Policy, stream.Stream["policy"])
assert.Equal(t, fixtures.MinimalTargetSendResult.Category, stream.Stream["category"])
assert.Equal(t, string(fixtures.MinimalTargetSendResult.Result), stream.Stream["result"])
assert.Equal(t, string(fixtures.MinimalTargetSendResult.Severity), stream.Stream["severity"])

assert.Equal(t, "policy-reporter", stream.Stream["createdBy"])
}

client := loki.NewClient(loki.Options{
ClientOptions: target.ClientOptions{
Name: "Loki",
},
Host: "http://localhost:3100/api/prom/push",
Host: "http://localhost:3100/loki/api/v1/push",
CustomFields: map[string]string{"custom": "label"},
HTTPClient: testClient{callback, 200},
})
Expand All @@ -172,7 +124,7 @@ func Test_LokiTarget(t *testing.T) {
ClientOptions: target.ClientOptions{
Name: "Loki",
},
Host: "http://localhost:3100/api/prom/push",
Host: "http://localhost:3100/loki/api/v1/push",
CustomFields: map[string]string{"custom": "label"},
HTTPClient: testClient{},
})
Expand All @@ -183,44 +135,16 @@ func Test_LokiTarget(t *testing.T) {
})
}

func convertAndValidateBody(req *http.Request, t *testing.T) (string, string) {
payload := make(map[string]interface{})
func convertAndValidateBody(req *http.Request, t *testing.T) loki.Stream {
payload := loki.Payload{}

err := json.NewDecoder(req.Body).Decode(&payload)
if err != nil {
t.Fatal(err)
}

streamsContent, ok := payload["streams"]
if !ok {
t.Errorf("Expected payload key 'streams' is missing")
}

streams := streamsContent.([]interface{})
if len(streams) != 1 {
t.Errorf("Expected one streams entry")
}

firstStream := streams[0].(map[string]interface{})
entriesContent, ok := firstStream["entries"]
if !ok {
t.Errorf("Expected stream key 'entries' is missing")
}
labels, ok := firstStream["labels"]
if !ok {
t.Errorf("Expected stream key 'labels' is missing")
}

entryContent := entriesContent.([]interface{})[0]
entry := entryContent.(map[string]interface{})
_, ok = entry["ts"]
if !ok {
t.Errorf("Expected entry key 'ts' is missing")
}
line, ok := entry["line"]
if !ok {
t.Errorf("Expected entry key 'line' is missing")
}
assert.Len(t, payload.Streams[0].Values, 1)
assert.Len(t, payload.Streams[0].Values[0], 2)

return labels.(string), line.(string)
return payload.Streams[0]
}

0 comments on commit 67f85e4

Please sign in to comment.