Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(bigTent slo): Custom Validate function for big tent SLO schema #2016

Merged
merged 50 commits into from
Mar 11, 2025
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
97b18b9
feat(bigTent slo): Custom Validate function for big tent SLO schema
Leo-DiCara Jan 31, 2025
ab44728
Merge branch 'main' into ld/big_tent_validate
Leo-DiCara Jan 31, 2025
4231bd0
feat(bigTent slo): Tests for custom validate functions
Leo-DiCara Feb 1, 2025
fa7583a
Merge branch 'ld/big_tent_validate' of github.com:grafana/terraform-p…
Leo-DiCara Feb 1, 2025
f514eb0
feat(bigTent slo): fmt
Leo-DiCara Feb 3, 2025
1efd39b
feat(bigTent slo): removing derpecated reliance
Leo-DiCara Feb 3, 2025
2c6b7c9
feat(bigTent slo): fmt
Leo-DiCara Feb 3, 2025
7da58a2
feat(bigTent slo): fmt
Leo-DiCara Feb 3, 2025
b16d7d6
Merge branch 'main' into ld/big_tent_validate
Leo-DiCara Feb 3, 2025
9697dc6
feat(bigTent slo): fix overzealous id refactor
Leo-DiCara Feb 3, 2025
73ebdf2
Merge branch 'ld/big_tent_validate' of github.com:grafana/terraform-p…
Leo-DiCara Feb 3, 2025
6b77ed8
feat(bigTent slo): ignore http redirect for link checker
Leo-DiCara Feb 4, 2025
964ddd4
Merge branch 'main' into ld/big_tent_validate
Leo-DiCara Feb 4, 2025
9dcb2f6
feat(bigTent slo): Drop warning on Prometheus queries
Leo-DiCara Feb 7, 2025
ffecf7e
Merge branch 'ld/big_tent_validate' of github.com:grafana/terraform-p…
Leo-DiCara Feb 7, 2025
6df417a
Merge branch 'main' into ld/big_tent_validate
Leo-DiCara Feb 7, 2025
e60b741
chore(bigTent slo): WIP update documentation
Leo-DiCara Feb 10, 2025
26d9371
Merge branch 'ld/big_tent_validate' of github.com:grafana/terraform-p…
Leo-DiCara Feb 11, 2025
4881fef
chore(bigTent slo): update documentation
Leo-DiCara Feb 11, 2025
a392c84
chore(bigTent slo): update documentation
Leo-DiCara Feb 11, 2025
ac83149
chore(bigTent slo): update documentation
Leo-DiCara Feb 11, 2025
ffd495b
chore(doc links): fixing terraform provider doc links
Leo-DiCara Feb 11, 2025
6fab993
chore(doc links): fixing terraform provider doc links
Leo-DiCara Feb 11, 2025
7341ebe
chore(doc links): fixing terraform provider doc links
Leo-DiCara Feb 11, 2025
e8877fa
chore(slo provider): update to new query type
Leo-DiCara Feb 18, 2025
ad17b07
Merge branch 'main' into ld/big_tent_validate
Leo-DiCara Feb 18, 2025
c1c19e9
chore(slo provider): fixing grafana_queries for tf format
Leo-DiCara Feb 18, 2025
3c90dc7
chore(slo provider): docs
Leo-DiCara Feb 18, 2025
b0ee9a4
chore(slo provider): update failure for prometheus queries in grafana…
Leo-DiCara Feb 18, 2025
6a566c4
chore(slo provider): fmt
Leo-DiCara Feb 18, 2025
100c49a
chore(slo provider): remove from ratio queries
Leo-DiCara Feb 20, 2025
d87e532
chore(slo provider): fix tf provider
Leo-DiCara Feb 21, 2025
c699182
chore(slo provider): fix plan from state
Leo-DiCara Feb 22, 2025
1826846
chore(slo provider): docs
Leo-DiCara Feb 22, 2025
d876c5e
chore(slo provider): remove println
Leo-DiCara Feb 24, 2025
60500ab
chore(slo provider): name change
Leo-DiCara Feb 25, 2025
112527c
chore(slo provider): PR comments
Leo-DiCara Feb 26, 2025
07f17f0
chore(slo provider): PR comments
Leo-DiCara Feb 26, 2025
3b4c723
Merge branch 'main' into ld/big_tent_validate
Leo-DiCara Feb 26, 2025
f713293
chore(slo provider): fixing fmt
Leo-DiCara Feb 26, 2025
4eeafbc
chore(slo provider): fixing fmt
Leo-DiCara Feb 26, 2025
df4df41
chore(slo provider): add graphite bad format test
Leo-DiCara Feb 26, 2025
4c1c8a9
chore(slo provider): add graphite bad format test
Leo-DiCara Feb 26, 2025
5bf0f28
chore(slo provider): fix graphite uid
Leo-DiCara Feb 26, 2025
26f2a1a
chore(slo provider): fix graphite uid
Leo-DiCara Feb 26, 2025
a5bc2b2
chore(slo provider): fix expected error message.
Leo-DiCara Feb 26, 2025
dc3c477
chore(slo provider): Rewording errors
Leo-DiCara Feb 28, 2025
e240570
chore(slo provider): Rewording errors
Leo-DiCara Feb 28, 2025
60a49ea
chore(slo provider): fmt
Leo-DiCara Feb 28, 2025
6710ea9
chore(slo provider): pr suggestions
Leo-DiCara Feb 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .linkcheckerrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ checkextern=1
ignore=
# https://regex101.com/r/Pl0jCn/1
\/\*\!sc\*\/
ignorewarningsforurls=
^https://jqlang\.github\.io/jq/ ^http-redirected

[MarkdownCheck]
filename_re=.*\.md
99 changes: 90 additions & 9 deletions internal/resources/slo/resource_slo.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package slo

import (
"context"
"encoding/json"
"fmt"
"regexp"

"github.com/grafana/slo-openapi-client/go/slo"

"github.com/grafana/terraform-provider-grafana/v3/internal/common"
"github.com/hashicorp/go-cty/cty"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
Expand Down Expand Up @@ -90,9 +92,10 @@ Resource manages Grafana SLOs.
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"query": {
Type: schema.TypeString,
Required: true,
Description: "Freeform Query Field",
Type: schema.TypeString,
Required: true,
Description: "Freeform Query Field",
ValidateDiagFunc: ValidateBigTent(),
},
},
},
Expand All @@ -104,14 +107,16 @@ Resource manages Grafana SLOs.
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"success_metric": {
Type: schema.TypeString,
Description: `Counter metric for success events (numerator)`,
Required: true,
Type: schema.TypeString,
Description: `Counter metric for success events (numerator)`,
Required: true,
ValidateDiagFunc: ValidateBigTent(),
},
"total_metric": {
Type: schema.TypeString,
Description: `Metric for total events (denominator)`,
Required: true,
Type: schema.TypeString,
Description: `Metric for total events (denominator)`,
Required: true,
ValidateDiagFunc: ValidateBigTent(),
},
"group_by_labels": {
Type: schema.TypeList,
Expand Down Expand Up @@ -661,3 +666,79 @@ func apiError(action string, err error) diag.Diagnostics {
},
}
}

func ValidateBigTent() schema.SchemaValidateDiagFunc {
return func(i interface{}, path cty.Path) diag.Diagnostics {
var diags diag.Diagnostics

v, ok := i.(string)
if !ok {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Bad Format",
Detail: fmt.Sprintf("expected type of %s to be string", path),
AttributePath: path,
})
}

var gmrQuery []map[string]any
err := json.Unmarshal([]byte(v), &gmrQuery)
if err != nil {
diags = append(diags, diag.Diagnostic{
Severity: diag.Warning,
Summary: "Bad JSON format",
Detail: "If this is a big tent query, this should be valid JSON. If this is a prometheus query, ignore this.",
AttributePath: path,
})
return diags
}

for _, queryObj := range gmrQuery {
currentPath := path.Copy()

refID, ok := queryObj["refId"]
if !ok {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Missing Required Field",
Detail: fmt.Sprintf("expected Big Tent Query %v to have a refId", queryObj),
AttributePath: append(currentPath, cty.IndexStep{Key: cty.StringVal("refId")}),
})
return diags
}

source := queryObj["datasource"]
s, ok := source.(map[string]interface{})
if !ok {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Missing Required Field",
Detail: fmt.Sprintf("expected Big Tent Query (refId:%v) to have a datasource", refID),
AttributePath: append(currentPath, cty.IndexStep{Key: cty.StringVal("datasource")}),
})
return diags
}

currentPath = append(currentPath, cty.IndexStep{Key: cty.StringVal("datasource")})
_, ok = s["type"]
if !ok {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Missing Required Field",
Detail: fmt.Sprintf("expected Big Tent Query (refId:%v) to have a type", refID),
AttributePath: append(currentPath.Copy(), cty.IndexStep{Key: cty.StringVal("type")}),
})
}
_, ok = s["uid"]
if !ok {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Missing Required Field",
Detail: fmt.Sprintf("expected Big Tent Query (refId:%v) to have a uid", refID),
Copy link
Contributor

@elainevuong elainevuong Feb 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: do we want to use "Big Tent" language in our error messages? how about "supported datasource must specify a datasource: uid" and or "datasource: type"

nit: did you want to specify datasource: uid rather than just uid? same comment for datasource: type above. since the uid and type fields are part of the datasource struct. this is what it looks like in the Terraform terminal (I removed the type field and then I removed the uid field - wanted to see how the error message appeared to a user)

Screenshot 2025-02-26 at 12 08 33 PM

AttributePath: append(currentPath.Copy(), cty.IndexStep{Key: cty.StringVal("uid")}),
})
}
}
return diags
}
}
168 changes: 168 additions & 0 deletions internal/resources/slo/resource_slo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@ package slo_test

import (
"context"
"encoding/json"
"errors"
"fmt"
"regexp"
"strings"
"testing"
"time"

"github.com/grafana/grafana-openapi-client-go/models"
slo2 "github.com/grafana/terraform-provider-grafana/v3/internal/resources/slo"
"github.com/hashicorp/go-cty/cty"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/stretchr/testify/assert"

"github.com/grafana/slo-openapi-client/go/slo"
"github.com/grafana/terraform-provider-grafana/v3/internal/common"
"github.com/grafana/terraform-provider-grafana/v3/internal/testutils"
Expand Down Expand Up @@ -412,3 +419,164 @@ func TestAccResourceInvalidSlo(t *testing.T) {
},
})
}

func TestValidateBigTent(t *testing.T) {
tests := map[string]struct {
query string
expectedDiags diag.Diagnostics
}{
"prometheus": {
query: "sum(rate(apiserver_request_total{code!=\"500\"}[$__rate_interval])) / sum(rate(apiserver_request_total[$__rate_interval]))",
expectedDiags: diag.Diagnostics{
diag.Diagnostic{
Severity: diag.Warning,
Summary: "Bad JSON format",
Detail: "If this is a big tent query, this should be valid JSON. If this is a prometheus query, ignore this.",
AttributePath: cty.IndexPath(cty.Value{}),
},
},
},
"bigTent_success": {
query: createBigTent(true, []map[string]any{}),
expectedDiags: diag.Diagnostics{},
},
"bigTent_noRefId": {
query: createBigTent(false, []map[string]any{{}}),
expectedDiags: diag.Diagnostics{
diag.Diagnostic{
Severity: diag.Error,
Summary: "Missing Required Field",
Detail: fmt.Sprintf("expected Big Tent Query %v to have a refId", "map[]"),
AttributePath: append(cty.IndexPath(cty.Value{}), cty.IndexStep{Key: cty.StringVal("refId")}),
},
},
},
"bigTent_noDatasource": {
query: createBigTent(false, []map[string]any{{"refId": "A"}}),
expectedDiags: diag.Diagnostics{
diag.Diagnostic{
Severity: diag.Error,
Summary: "Missing Required Field",
Detail: "expected Big Tent Query (refId:A) to have a datasource",
AttributePath: append(cty.IndexPath(cty.Value{}), cty.IndexStep{Key: cty.StringVal("datasource")}),
},
},
},
"bigTent_missingFields": {
query: createBigTent(false, []map[string]any{{"refId": "A", "datasource": models.DataSource{}}}),
expectedDiags: diag.Diagnostics{
diag.Diagnostic{
Severity: diag.Error,
Summary: "Missing Required Field",
Detail: "expected Big Tent Query (refId:A) to have a type",
AttributePath: append(cty.IndexPath(cty.Value{}), cty.IndexStep{Key: cty.StringVal("datasource")}, cty.IndexStep{Key: cty.StringVal("type")}),
},
diag.Diagnostic{
Severity: diag.Error,
Summary: "Missing Required Field",
Detail: "expected Big Tent Query (refId:A) to have a uid",
AttributePath: append(cty.IndexPath(cty.Value{}), cty.IndexStep{Key: cty.StringVal("datasource")}, cty.IndexStep{Key: cty.StringVal("uid")}),
},
},
},
}
testFunc := slo2.ValidateBigTent()

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
diags := testFunc(tc.query, cty.IndexPath(cty.Value{}))

require.Len(t, diags, len(tc.expectedDiags))
for i, w := range tc.expectedDiags {
assert.Equal(t, w, diags[i])
}
})
}
}

func createBigTent(useDefault bool, input []map[string]any) string {
const bigTentQuery = `
[
{
"aggregation": "Sum",
"alias": "",
"application": "57831",
"applicationName": "petclinic",
"datasource": {
"type": "dlopes7-appdynamics-datasource",
"uid": "appdynamics_localdev"
},
"delimiter": "|",
"isRawQuery": false,
"metric": "Overall Application Performance|Calls per Minute",
"queryType": "metrics",
"refId": "total",
"rollUp": true,
"schemaVersion": "3.9.5",
"transformLegend": "Segments",
"transformLegendText": ""
},
{
"aggregation": "Sum",
"alias": "",
"application": "57831",
"applicationName": "petclinic",
"datasource": {
"type": "dlopes7-appdynamics-datasource",
"uid": "appdynamics_localdev"
},
"intervalMs": 1000,
"maxDataPoints": 43200,
"delimiter": "|",
"isRawQuery": false,
"metric": "Overall Application Performance|Calls per Minute",
"queryType": "metrics",
"refId": "also_total",
"rollUp": true,
"schemaVersion": "3.9.5",
"transformLegend": "Segments",
"transformLegendText": ""
},
{
"conditions": [
{
"evaluator": {
"params": [
0,
0
],
"type": "gt"
},
"operator": {
"type": "and"
},
"query": {
"params": []
},
"reducer": {
"params": [],
"type": "avg"
},
"type": "query"
}
],
"datasource": {
"name": "Expression",
"type": "__expr__",
"uid": "__expr__"
},
"expression": "($total / $also_total)",
"intervalMs": 1000,
"maxDataPoints": 43200,
"refId": "C",
"type": "math"
}
]`

if useDefault {
return bigTentQuery
}

output, _ := json.Marshal(input)
return string(output)
}
Loading