Skip to content

Commit

Permalink
Add template variable support to Terraform provider (#126)
Browse files Browse the repository at this point in the history
  • Loading branch information
carolynblumberg committed Mar 13, 2023
1 parent 087a807 commit 519424d
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .go-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.73.1
1.73.2
26 changes: 17 additions & 9 deletions client/metric_dashboards.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ type UnifiedDashboard struct {
}

type UnifiedDashboardAttributes struct {
Name string `json:"name"`
Description string `json:"description"`
Charts []UnifiedChart `json:"charts"`
Groups []UnifiedGroup `json:"groups"`
Labels []Label `json:"labels"`
Name string `json:"name"`
Description string `json:"description"`
Charts []UnifiedChart `json:"charts"`
Groups []UnifiedGroup `json:"groups"`
Labels []Label `json:"labels"`
TemplateVariables []TemplateVariable `json:"template_variables"`
}

type UnifiedGroup struct {
Expand Down Expand Up @@ -63,6 +64,12 @@ type MetricGroupBy struct {
AggregationMethod string `json:"aggregation-method"`
}

type TemplateVariable struct {
Name string `json:"name"`
DefaultValues []string `json:"default_values"`
SuggestionAttributeKey string `json:"suggestion_attribute_key"`
}

func getUnifiedDashboardURL(project, id string, query map[string]string) string {
path := fmt.Sprintf(
"projects/%s/metric_dashboards",
Expand Down Expand Up @@ -95,10 +102,11 @@ func (c *Client) CreateUnifiedDashboard(
bytes, err := json.Marshal(UnifiedDashboard{
Type: dashboard.Type,
Attributes: UnifiedDashboardAttributes{
Name: dashboard.Attributes.Name,
Description: dashboard.Attributes.Description,
Groups: dashboard.Attributes.Groups,
Labels: dashboard.Attributes.Labels,
Name: dashboard.Attributes.Name,
Description: dashboard.Attributes.Description,
Groups: dashboard.Attributes.Groups,
Labels: dashboard.Attributes.Labels,
TemplateVariables: dashboard.Attributes.TemplateVariables,
},
})

Expand Down
21 changes: 19 additions & 2 deletions docs/resources/dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ resource "lightstep_dashboard" "customer_charges" {
dashboard_description = "Dashboard for customer charges metrics"
chart {
name = "Requests by Project"
name = "Requests by Project for $service"
rank = 1
type = "timeseries"
query {
hidden = false
query_name = "a"
display = "line"
query_string = "metric requests | rate 10m | group_by [project_id], sum"
query_string = "metric requests | filter (service == $service) | rate 10m | group_by [project_id], sum"
}
}
Expand All @@ -53,6 +53,12 @@ resource "lightstep_dashboard" "customer_charges" {
label {
value = "customlabel"
}
template_variable {
name = "service"
default_values = ["adservice"]
suggestion_attribute_key = "service_name"
}
}
```

Expand All @@ -70,6 +76,7 @@ resource "lightstep_dashboard" "customer_charges" {
- `dashboard_description` (String)
- `group` (Block Set) (see [below for nested schema](#nestedblock--group))
- `label` (Block Set) Labels can be key/value pairs or standalone values. (see [below for nested schema](#nestedblock--label))
- `template_variable` (Block Set) Variable to be used in dashboard queries for dynamically filtering telemetry data (see [below for nested schema](#nestedblock--template_variable))

### Read-Only

Expand Down Expand Up @@ -216,3 +223,13 @@ Required:
Optional:

- `key` (String)


<a id="nestedblock--template_variable"></a>
### Nested Schema for `template_variable`

Required:

- `default_values` (List of String) One or more values to set the template variable to by default (if none are provided, defaults to all possible values)
- `name` (String) Unique (per dashboard) name for template variable, beginning with a letter or underscore and only containing letters, numbers, and underscores
- `suggestion_attribute_key` (String) Attribute key used as source for suggested template variable values appearing in Lightstep UI
11 changes: 11 additions & 0 deletions docs/resources/metric_dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ resource "lightstep_metric_dashboard" "customer_charges" {
- `dashboard_description` (String)
- `group` (Block Set) (see [below for nested schema](#nestedblock--group))
- `label` (Block Set) Labels can be key/value pairs or standalone values. (see [below for nested schema](#nestedblock--label))
- `template_variable` (Block Set) Variable to be used in dashboard queries for dynamically filtering telemetry data (see [below for nested schema](#nestedblock--template_variable))

### Read-Only

Expand Down Expand Up @@ -302,3 +303,13 @@ Required:
Optional:

- `key` (String)


<a id="nestedblock--template_variable"></a>
### Nested Schema for `template_variable`

Required:

- `default_values` (List of String) One or more values to set the template variable to by default (if none are provided, defaults to all possible values)
- `name` (String) Unique (per dashboard) name for template variable, beginning with a letter or underscore and only containing letters, numbers, and underscores
- `suggestion_attribute_key` (String) Attribute key used as source for suggested template variable values appearing in Lightstep UI
78 changes: 78 additions & 0 deletions lightstep/resource_dashboard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,84 @@ resource "lightstep_dashboard" "labels" {
})
}

func TestAccDashboardWithTemplateVariables(t *testing.T) {
validDashboardConfigWithTemplateVariables := `
resource "lightstep_dashboard" "test" {
project_name = "terraform-provider-tests"
dashboard_name = "Acceptance Test Dashboard with Template Variables"
chart {
name = "Chart Number One"
rank = 1
type = "timeseries"
query {
hidden = false
query_name = "a"
display = "line"
query_string = "metric m | filter (service == $service) | rate | group_by [], sum"
}
}
template_variable {
name = "service"
default_values = ["myService"]
suggestion_attribute_key = "service_name"
}
}
`

invalidDashboardConfigWithInvalidTemplateVariableName := `
resource "lightstep_dashboard" "test" {
project_name = "terraform-provider-tests"
dashboard_name = "Acceptance Test Dashboard"
chart {
name = "Chart Number One"
rank = 1
type = "timeseries"
query {
hidden = false
query_name = "a"
display = "line"
query_string = "metric m | filter (service == $invalid-name) | rate | group_by [], sum"
}
}
template_variable {
name = "invalid-name"
default_values = ["myService"]
suggestion_attribute_key = "service_name"
}
}
`

var dashboard client.UnifiedDashboard
resourceName := "lightstep_dashboard.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: testAccProviderFactories,
CheckDestroy: testGetMetricDashboardDestroy,
Steps: []resource.TestStep{
{
Config: validDashboardConfigWithTemplateVariables,
Check: resource.ComposeTestCheckFunc(
testAccCheckMetricDashboardExists(resourceName, &dashboard),
resource.TestCheckResourceAttr(resourceName, "dashboard_name", "Acceptance Test Dashboard with Template Variables"),
resource.TestCheckResourceAttr(resourceName, "chart.0.query.0.query_string", "metric m | filter (service == $service) | rate | group_by [], sum"),
resource.TestCheckResourceAttr(resourceName, "chart.0.query.0.display", "line"),
resource.TestCheckResourceAttr(resourceName, "chart.0.query.0.hidden", "false"),
resource.TestCheckResourceAttr(resourceName, "template_variable.0.name", "service"),
resource.TestCheckResourceAttr(resourceName, "template_variable.0.default_values.0", "myService"),
resource.TestCheckResourceAttr(resourceName, "template_variable.0.suggestion_attribute_key", "service_name"),
),
},
{
Config: invalidDashboardConfigWithInvalidTemplateVariableName,
Check: resource.ComposeTestCheckFunc(
testAccCheckMetricDashboardExists(resourceName, &dashboard)),
ExpectError: regexp.MustCompile("InvalidArgument"),
},
},
})
}

func testGetMetricDashboardDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*client.Client)
for _, r := range s.RootModule().Resources {
Expand Down
81 changes: 77 additions & 4 deletions lightstep/resource_metric_dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,14 @@ func resourceUnifiedDashboard(chartSchemaType ChartSchemaType) *schema.Resource
},
},
},
"template_variable": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: getTemplateVariableSchema(),
},
Description: "Variable to be used in dashboard queries for dynamically filtering telemetry data",
},
},
}
}
Expand Down Expand Up @@ -219,6 +227,29 @@ func getChartSchema(chartSchemaType ChartSchemaType) map[string]*schema.Schema {
}
}

func getTemplateVariableSchema() map[string]*schema.Schema {
return map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "Unique (per dashboard) name for template variable, beginning with a letter or underscore and only containing letters, numbers, and underscores",
},
"suggestion_attribute_key": {
Type: schema.TypeString,
Required: true,
Description: "Attribute key used as source for suggested template variable values appearing in Lightstep UI",
},
"default_values": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Description: "One or more values to set the template variable to by default (if none are provided, defaults to all possible values)",
},
}
}

type resourceUnifiedDashboardImp struct {
chartSchemaType ChartSchemaType
}
Expand Down Expand Up @@ -363,11 +394,15 @@ func getUnifiedDashboardAttributesFromResource(d *schema.ResourceData) (*client.
return nil, err
}

templateVariableSet := d.Get("template_variable").(*schema.Set)
templateVariables := buildTemplateVariables(templateVariableSet.List())

attributes := &client.UnifiedDashboardAttributes{
Name: d.Get("dashboard_name").(string),
Description: d.Get("dashboard_description").(string),
Groups: groups,
Labels: labels,
Name: d.Get("dashboard_name").(string),
Description: d.Get("dashboard_description").(string),
Groups: groups,
Labels: labels,
TemplateVariables: templateVariables,
}

return attributes, nil
Expand Down Expand Up @@ -519,6 +554,31 @@ func buildYAxis(yAxisIn []interface{}) (*client.YAxis, error) {
return yAxis, nil
}

func buildTemplateVariables(templateVariablesIn []interface{}) []client.TemplateVariable {
var newTemplateVariables []client.TemplateVariable
for _, tv := range templateVariablesIn {
tvMap := tv.(map[string]interface{})
name := tvMap["name"].(string)
suggestionAttributeKey := tvMap["suggestion_attribute_key"].(string)
defaultValues := buildDefaultValues(tvMap["default_values"].([]interface{}))

newTemplateVariables = append(newTemplateVariables, client.TemplateVariable{
Name: name,
DefaultValues: defaultValues,
SuggestionAttributeKey: suggestionAttributeKey,
})
}
return newTemplateVariables
}

func buildDefaultValues(valuesIn []interface{}) []string {
defaultValues := make([]string, 0, len(valuesIn))
for _, v := range valuesIn {
defaultValues = append(defaultValues, v.(string))
}
return defaultValues
}

func (p *resourceUnifiedDashboardImp) setResourceDataFromUnifiedDashboard(project string, dash client.UnifiedDashboard, d *schema.ResourceData) error {
if err := d.Set("project_name", project); err != nil {
return fmt.Errorf("unable to set project_name resource field: %v", err)
Expand Down Expand Up @@ -618,6 +678,19 @@ func (p *resourceUnifiedDashboardImp) setResourceDataFromUnifiedDashboard(projec
return fmt.Errorf("unable to set labels resource field: %v", err)
}

var templateVariables []interface{}
for _, tv := range dash.Attributes.TemplateVariables {
templateVariable := map[string]interface{}{}
templateVariable["name"] = tv.Name
templateVariable["default_values"] = tv.DefaultValues
templateVariable["suggestion_attribute_key"] = tv.SuggestionAttributeKey

templateVariables = append(templateVariables, templateVariable)
}
if err := d.Set("template_variable", templateVariables); err != nil {
return fmt.Errorf("unable to set template variables resource field: %v", err)
}

return nil
}

Expand Down
10 changes: 8 additions & 2 deletions templates/resources/dashboard.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ resource "lightstep_dashboard" "customer_charges" {
dashboard_description = "Dashboard for customer charges metrics"

chart {
name = "Requests by Project"
name = "Requests by Project for $service"
rank = 1
type = "timeseries"

query {
hidden = false
query_name = "a"
display = "line"
query_string = "metric requests | rate 10m | group_by [project_id], sum"
query_string = "metric requests | filter (service == $service) | rate 10m | group_by [project_id], sum"
}
}

Expand All @@ -53,6 +53,12 @@ resource "lightstep_dashboard" "customer_charges" {
label {
value = "customlabel"
}

template_variable {
name = "service"
default_values = ["adservice"]
suggestion_attribute_key = "service_name"
}
}
```

Expand Down

0 comments on commit 519424d

Please sign in to comment.