Skip to content

Commit

Permalink
Migrate opentsdb string fields to int (#401)
Browse files Browse the repository at this point in the history
This fixes a migration bug introduced by #398
We unfortunately have to add a schema migration function to convert the strings to int
Since 1.20.0 is released, we cannot just go back to a string at this point, so a migration is the way forward

Fixes #400
We should release 1.20.1 once that's merged
  • Loading branch information
julienduchesne committed Feb 24, 2022
1 parent 2828480 commit b62ecac
Show file tree
Hide file tree
Showing 2 changed files with 190 additions and 4 deletions.
66 changes: 62 additions & 4 deletions grafana/resource_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ The required arguments for this resource vary depending on the type of data
source selected (via the 'type' argument).
`,

CreateContext: CreateDataSource,
UpdateContext: UpdateDataSource,
DeleteContext: DeleteDataSource,
ReadContext: ReadDataSource,
CreateContext: CreateDataSource,
UpdateContext: UpdateDataSource,
DeleteContext: DeleteDataSource,
ReadContext: ReadDataSource,
StateUpgraders: []schema.StateUpgrader{resourceDataSourceV0Upgrader},
SchemaVersion: 1,

// Import either by ID or UID
Importer: &schema.ResourceImporter{
Expand Down Expand Up @@ -704,3 +706,59 @@ func makeSecureJSONData(d *schema.ResourceData) gapi.SecureJSONData {
TLSClientKey: d.Get("secure_json_data.0.tls_client_key").(string),
}
}

// TSDB Version and Resolution used to be strings, but now are integers.
func resourceDataSourceV0Schema() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
"json_data": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"tsdb_resolution": {
Type: schema.TypeInt,
Optional: true,
Description: "(OpenTSDB) Resolution.",
},
"tsdb_version": {
Type: schema.TypeInt,
Optional: true,
Description: "(OpenTSDB) Version.",
},
},
},
},
},
}
}

var resourceDataSourceV0Upgrader = schema.StateUpgrader{
Version: 0,
Type: resourceDataSourceV0Schema().CoreConfigSchema().ImpliedType(),
Upgrade: func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) {
convertToInt := func(m map[string]interface{}, key string) {
if value, hasValue := m[key]; hasValue {
m[key] = 0
if valueStr, ok := value.(string); ok {
if valueInt, err := strconv.Atoi(valueStr); err == nil {
m[key] = valueInt
}
}
}
}

var jsonData map[string]interface{}
if jsonDataList, ok := rawState["json_data"].([]interface{}); ok && len(jsonDataList) > 0 {
jsonData = jsonDataList[0].(map[string]interface{})
} else if jsonDataMap, ok := rawState["json_data"].(map[string]interface{}); ok {
jsonData = jsonDataMap
}
if jsonData != nil {
convertToInt(jsonData, "tsdb_version")
convertToInt(jsonData, "tsdb_resolution")
}

return rawState, nil
},
}
128 changes: 128 additions & 0 deletions grafana/resource_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package grafana

import (
"fmt"
"reflect"
"strconv"
"testing"

Expand Down Expand Up @@ -566,6 +567,133 @@ func TestAccDataSource_basic(t *testing.T) {
}
}

func TestDatasourceMigrationV0(t *testing.T) {
cases := []struct {
name string
state map[string]interface{}
expected map[string]interface{}
}{
{
name: "no json data",
state: map[string]interface{}{
"name": "test",
"type": "prometheus",
},
expected: map[string]interface{}{
"name": "test",
"type": "prometheus",
},
},
{
name: "no tsdb fields",
state: map[string]interface{}{
"name": "test",
"type": "prometheus",
"json_data": []map[string]interface{}{
{
"url": "http://localhost:9090",
},
},
},
expected: map[string]interface{}{
"name": "test",
"type": "prometheus",
"json_data": []map[string]interface{}{
{
"url": "http://localhost:9090",
},
},
},
},
{
name: "nil or empty tsdb fields",
state: map[string]interface{}{
"name": "test",
"type": "test",
"json_data": []map[string]interface{}{
{
"tsdb_version": "",
"tsdb_resolution": nil,
"url": "http://localhost:9090",
},
},
},
expected: map[string]interface{}{
"name": "test",
"type": "test",
"json_data": []map[string]interface{}{
{
"tsdb_version": 0,
"tsdb_resolution": 0,
"url": "http://localhost:9090",
},
},
},
},
{
name: "already int",
state: map[string]interface{}{
"name": "test",
"type": "test",
"json_data": []map[string]interface{}{
{
"tsdb_version": 0,
"tsdb_resolution": 2,
"url": "http://localhost:9090",
},
},
},
expected: map[string]interface{}{
"name": "test",
"type": "test",
"json_data": []map[string]interface{}{
{
"tsdb_version": 0,
"tsdb_resolution": 2,
"url": "http://localhost:9090",
},
},
},
},
{
name: "migration",
state: map[string]interface{}{
"name": "test",
"type": "test",
"json_data": []map[string]interface{}{
{
"tsdb_version": "0",
"tsdb_resolution": "2",
"url": "http://localhost:9090",
},
},
},
expected: map[string]interface{}{
"name": "test",
"type": "test",
"json_data": []map[string]interface{}{
{
"tsdb_version": 0,
"tsdb_resolution": 2,
"url": "http://localhost:9090",
},
},
},
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
actual, err := resourceDataSourceV0Upgrader.Upgrade(nil, tc.expected, nil)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(actual, tc.expected) {
t.Errorf("Expected %#v, got %#v", tc.expected, actual)
}
})
}
}

func testAccDataSourceCheckExists(rn string, dataSource *gapi.DataSource) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[rn]
Expand Down

0 comments on commit b62ecac

Please sign in to comment.