Repository: honeycombio/terraform-provider-honeycombio
Pull request #203 (2022-08-03 17:00:10)

Remove Board inline queries support from client and deprecate board queries' 'dataset'


Patch:
diff --git a/client/board.go b/client/board.go
index ae83f3f..ca409e9 100644
--- a/client/board.go
+++ b/client/board.go
@@ -71,11 +71,10 @@ type BoardQuery struct {
 	Caption string `json:"caption,omitempty"`
 	// Defaults to graph.
 	QueryStyle BoardQueryStyle `json:"query_style,omitempty"`
-	// This field is required.
-	Dataset string `json:"dataset"`
-	// Either QueryID or Query is required.
-	QueryID string     `json:"query_id,omitempty"`
-	Query   *QuerySpec `json:"query,omitempty"`
+	// Dataset is no longer required
+	Dataset string `json:"dataset,omitempty"`
+	// QueryID is required
+	QueryID string `json:"query_id,omitempty"`
 	// Optional
 	QueryAnnotationID string `json:"query_annotation_id,omitempty"`
 }
diff --git a/client/dataset.go b/client/dataset.go
index 0e14f05..aa61afd 100644
--- a/client/dataset.go
+++ b/client/dataset.go
@@ -2,6 +2,7 @@ package client
 
 import (
 	"context"
+	"time"
 )
 
 // Datasets describes all the dataset-related methods that the Honeycomb API
@@ -35,6 +36,10 @@ var _ Datasets = (*datasets)(nil)
 type Dataset struct {
 	Name string `json:"name"`
 	Slug string `json:"slug,omitempty"`
+
+	// Read only
+	LastWrittenAt time.Time `json:"last_written_at,omitempty"`
+	CreatedAt     time.Time `json:"created_at,omitempty"`
 }
 
 func (s datasets) List(ctx context.Context) ([]Dataset, error) {
diff --git a/docs/resources/board.md b/docs/resources/board.md
index ef2ff3b..a781352 100644
--- a/docs/resources/board.md
+++ b/docs/resources/board.md
@@ -82,7 +82,6 @@ resource "honeycombio_board" "overview" {
   style       = "visual"
 
   query {
-    dataset             = var.dataset
     caption             = "Latency by User"
     query_id            = honeycombio_query.latency_by_userid.id
     query_annotation_id = honeycombio_query_annotation.latency_by_userid.id
@@ -103,7 +102,7 @@ Each board configuration may have zero or more `query` blocks, which accepts the
 
 * `query_id` - (Required) The ID of the Query to run.
 * `query_annotation_id` - (Optional) The ID of the Query Annotation to associate with this query.
-* `dataset` - (Required) The dataset this query is associated with.
+* `dataset` - (Deprecated) The dataset this query is associated with.
 * `caption` - (Optional) A description of the query that will be displayed on the board. Supports markdown.
 * `query_style` - (Optional) How the query should be displayed within the board, either `graph` (the default), `table` or `combo`.
 
diff --git a/docs/resources/dataset.md b/docs/resources/dataset.md
index e7de3c1..6bb7ad2 100644
--- a/docs/resources/dataset.md
+++ b/docs/resources/dataset.md
@@ -25,3 +25,5 @@ The following arguments are supported:
 In addition to all arguments above, the following attributes are exported:
 
 * `slug` - The slug of the dataset.
+* `created_at` - ISO8601 formatted time the column was created
+* `last_written_at` - ISO8601 formatted time the column was last written to (received event data)
diff --git a/example/board/main.tf b/example/board/main.tf
index 31ee59e..c5b65e8 100644
--- a/example/board/main.tf
+++ b/example/board/main.tf
@@ -41,7 +41,6 @@ resource "honeycombio_board" "board" {
 
   query {
     caption  = "Latency"
-    dataset  = var.dataset
     query_id = honeycombio_query.query.id
   }
 }
diff --git a/example/board_with_annotations/main.tf b/example/board_with_annotations/main.tf
index ea0aa95..31051f7 100644
--- a/example/board_with_annotations/main.tf
+++ b/example/board_with_annotations/main.tf
@@ -59,7 +59,6 @@ See the [wiki](https://wiki.company.internal.tld) for more information.
 EOT
 
   query {
-    dataset             = var.dataset
     caption             = "Latency by User"
     query_id            = honeycombio_query.latency_by_userid.id
     query_annotation_id = honeycombio_query_annotation.latency_by_userid.id
diff --git a/honeycombio/resource_board.go b/honeycombio/resource_board.go
index 6e9926c..0565d72 100644
--- a/honeycombio/resource_board.go
+++ b/honeycombio/resource_board.go
@@ -53,8 +53,10 @@ func newBoard() *schema.Resource {
 							ValidateFunc: validation.StringInSlice(boardQueryStyleStrings(), false),
 						},
 						"dataset": {
-							Type:     schema.TypeString,
-							Required: true,
+							Type:       schema.TypeString,
+							Optional:   true,
+							Computed:   true,
+							Deprecated: "Board Queries no longer require the dataset as they rely on the provided Query ID's dataset.",
 						},
 						"query_id": {
 							Type:     schema.TypeString,
diff --git a/honeycombio/resource_dataset.go b/honeycombio/resource_dataset.go
index a001411..ba50ca9 100644
--- a/honeycombio/resource_dataset.go
+++ b/honeycombio/resource_dataset.go
@@ -2,6 +2,7 @@ package honeycombio
 
 import (
 	"context"
+	"time"
 
 	"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
 	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -27,6 +28,18 @@ func newDataset() *schema.Resource {
 				Type:     schema.TypeString,
 				Computed: true,
 			},
+			"created_at": {
+				Type:     schema.TypeString,
+				Computed: true,
+				Required: false,
+				Optional: false,
+			},
+			"last_written_at": {
+				Type:     schema.TypeString,
+				Computed: true,
+				Required: false,
+				Optional: false,
+			},
 		},
 	}
 }
@@ -60,5 +73,7 @@ func resourceDatasetRead(ctx context.Context, d *schema.ResourceData, meta inter
 	d.SetId(dataset.Slug)
 	d.Set("name", dataset.Name)
 	d.Set("slug", dataset.Slug)
+	d.Set("created_at", dataset.CreatedAt.UTC().Format(time.RFC3339))
+	d.Set("last_written_at", dataset.CreatedAt.UTC().Format(time.RFC3339))
 	return nil
 }


Test patch:
diff --git a/client/board_test.go b/client/board_test.go
index 1b0e07d..61b61ae 100644
--- a/client/board_test.go
+++ b/client/board_test.go
@@ -18,6 +18,17 @@ func TestBoards(t *testing.T) {
 	c := newTestClient(t)
 	dataset := testDataset(t)
 
+	query, err := c.Queries.Create(ctx, dataset, &QuerySpec{
+		Calculations: []CalculationSpec{
+			{
+				Op:     CalculationOpAvg,
+				Column: StringPtr("duration_ms"),
+			},
+		},
+		TimeRange: IntPtr(3600), // 1 hour
+	})
+	assert.NoError(t, err)
+
 	t.Run("Create", func(t *testing.T) {
 		data := &Board{
 			Name:        fmt.Sprintf("Test Board, created at %v", time.Now()),
@@ -28,23 +39,13 @@ func TestBoards(t *testing.T) {
 					Caption:    "A sample query",
 					QueryStyle: BoardQueryStyleCombo,
 					Dataset:    dataset,
-					Query: &QuerySpec{
-						Calculations: []CalculationSpec{
-							{
-								Op:     CalculationOpAvg,
-								Column: StringPtr("duration_ms"),
-							},
-						},
-						TimeRange: IntPtr(3600), // 1 hour
-					},
+					QueryID:    *query.ID,
 				},
 			},
 		}
 		b, err = c.Boards.Create(ctx, data)
 
-		if err != nil {
-			t.Fatal(err)
-		}
+		assert.NoError(t, err)
 		assert.NotNil(t, b.ID)
 
 		// copy ID before asserting equality
@@ -63,33 +64,28 @@ func TestBoards(t *testing.T) {
 
 	t.Run("Get", func(t *testing.T) {
 		board, err := c.Boards.Get(ctx, b.ID)
-		if err != nil {
-			t.Fatal(err)
-		}
+		assert.NoError(t, err)
 
 		assert.Equal(t, *b, *board)
 	})
 
 	t.Run("Update", func(t *testing.T) {
-		b.Queries[0].QueryID = ""
+		newQuery, err := c.Queries.Create(ctx, dataset, &QuerySpec{
+			Calculations: []CalculationSpec{
+				{
+					Op: CalculationOpCount,
+				},
+			},
+			TimeRange: IntPtr(7200), // 2 hours
+		})
+		assert.NoError(t, err)
 		b.Queries = append(b.Queries, BoardQuery{
 			Caption:    "A second query",
 			QueryStyle: BoardQueryStyleGraph,
-			Dataset:    dataset,
-			Query: &QuerySpec{
-				Calculations: []CalculationSpec{
-					{
-						Op: CalculationOpCount,
-					},
-				},
-				TimeRange: IntPtr(7200), // 2 hours
-			},
+			QueryID:    *newQuery.ID,
 		})
 
 		result, err := c.Boards.Update(ctx, b)
-		b.Queries[0].QueryID = result.Queries[0].QueryID
-		b.Queries[1].QueryID = result.Queries[1].QueryID
-
 		assert.NoError(t, err)
 		assert.Equal(t, b, result)
 	})
diff --git a/client/dataset_test.go b/client/dataset_test.go
index ff4f7eb..1ba71fa 100644
--- a/client/dataset_test.go
+++ b/client/dataset_test.go
@@ -22,6 +22,16 @@ func TestDatasets(t *testing.T) {
 		d, err := c.Datasets.List(ctx)
 
 		assert.NoError(t, err)
+
+		for _, dataset := range d {
+			assert.NotNil(t, dataset.LastWrittenAt, "last written at is empty")
+			assert.NotNil(t, dataset.CreatedAt, "created at is empty")
+			// copy dynamic fields before asserting - will be skipped if expected dataset not found
+			if dataset.Name == currentDataset.Name {
+				currentDataset.LastWrittenAt = dataset.LastWrittenAt
+				currentDataset.CreatedAt = dataset.CreatedAt
+			}
+		}
 		assert.Contains(t, d, *currentDataset, "could not find current dataset with List")
 	})
 
@@ -29,6 +39,13 @@ func TestDatasets(t *testing.T) {
 		d, err := c.Datasets.Get(ctx, currentDataset.Slug)
 
 		assert.NoError(t, err)
+
+		assert.NotNil(t, d.LastWrittenAt, "last written at is empty")
+		assert.NotNil(t, d.CreatedAt, "created at is empty")
+		// copy dynamic fields before asserting equality
+		d.LastWrittenAt = currentDataset.LastWrittenAt
+		d.CreatedAt = currentDataset.CreatedAt
+
 		assert.Equal(t, *currentDataset, *d)
 	})
 
@@ -45,6 +62,13 @@ func TestDatasets(t *testing.T) {
 		d, err := c.Datasets.Create(ctx, createDataset)
 
 		assert.NoError(t, err)
+
+		assert.NotNil(t, d.LastWrittenAt, "last written at is empty")
+		assert.NotNil(t, d.CreatedAt, "created at is empty")
+		// copy dynamic fields before asserting equality
+		d.LastWrittenAt = currentDataset.LastWrittenAt
+		d.CreatedAt = currentDataset.CreatedAt
+
 		assert.Equal(t, currentDataset, d)
 	})
 }
diff --git a/client/query_spec_test.go b/client/query_spec_test.go
index 226a565..b835e8d 100644
--- a/client/query_spec_test.go
+++ b/client/query_spec_test.go
@@ -2,14 +2,12 @@ package client
 
 import (
 	"context"
-	"fmt"
 	"testing"
-	"time"
 
 	"github.com/stretchr/testify/assert"
 )
 
-// create a board with an elaborate QuerySpec as smoke test
+// create a query with an elaborate QuerySpec as smoke test
 func TestQuerySpec(t *testing.T) {
 	ctx := context.Background()
 
@@ -70,140 +68,6 @@ func TestQuerySpec(t *testing.T) {
 		Granularity: IntPtr(60),   // 1 minute
 	}
 
-	b := &Board{
-		Name: fmt.Sprintf("Test QuerySpec, created at %v", time.Now()),
-
-		Queries: []BoardQuery{
-			{
-				Dataset: dataset,
-				Query:   &query,
-			},
-		},
-	}
-
-	b, err := c.Boards.Create(ctx, b)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer func() {
-		err := c.Boards.Delete(ctx, b.ID)
-		if err != nil {
-			t.Fatal(err)
-		}
-	}()
-
-	assert.Len(t, b.Queries, 1)
-	assert.Equal(t, &query, b.Queries[0].Query)
-}
-
-func TestCalcuationOps(t *testing.T) {
-	ctx := context.Background()
-	c := newTestClient(t)
-	dataset := testDataset(t)
-
-	b := &Board{
-		Name: "go-honeycombio: TestCalcula§tionOps",
-	}
-	b, err := c.Boards.Create(ctx, b)
-	assert.NoError(t, err)
-
-	defer c.Boards.Delete(ctx, b.ID)
-
-	for _, calculationOp := range CalculationOps() {
-		column := StringPtr("duration_ms")
-		if calculationOp.IsUnaryOp() {
-			column = nil
-		}
-
-		q := QuerySpec{
-			Calculations: []CalculationSpec{
-				{
-					Op:     calculationOp,
-					Column: column,
-				},
-			},
-		}
-		b.Queries = []BoardQuery{{Dataset: dataset, Query: &q}}
-
-		_, err = c.Boards.Update(ctx, b)
-		assert.NoError(t, err, fmt.Sprintf("Failed to create board that contains calcuation with op \"%v\"", calculationOp))
-	}
-}
-
-func TestFilterOps(t *testing.T) {
-	ctx := context.Background()
-	c := newTestClient(t)
-	dataset := testDataset(t)
-
-	b := &Board{
-		Name: "go-honeycombio: TestFilterOps",
-	}
-	b, err := c.Boards.Create(ctx, b)
+	_, err := c.Queries.Create(ctx, dataset, &query)
 	assert.NoError(t, err)
-
-	defer c.Boards.Delete(ctx, b.ID)
-
-	for _, filterOp := range FilterOps() {
-		var value interface{}
-
-		switch filterOp {
-		case FilterOpExists, FilterOpDoesNotExist:
-			value = nil
-		case FilterOpIn, FilterOpNotIn:
-			value = []string{"foo", "bar"}
-		default:
-			value = "foo"
-		}
-
-		q := QuerySpec{
-			Filters: []FilterSpec{
-				{
-					Column: "column_1",
-					Op:     filterOp,
-					Value:  value,
-				},
-			},
-		}
-		b.Queries = []BoardQuery{{Dataset: dataset, Query: &q}}
-
-		_, err = c.Boards.Update(ctx, b)
-		assert.NoError(t, err, fmt.Sprintf("Failed to create board that contains filter with op \"%v\"", filterOp))
-	}
-}
-
-func TestHavingOps(t *testing.T) {
-	ctx := context.Background()
-	c := newTestClient(t)
-	dataset := testDataset(t)
-
-	b := &Board{
-		Name: "go-honeycombio: TestHavingOps",
-	}
-	b, err := c.Boards.Create(ctx, b)
-	assert.NoError(t, err)
-
-	defer c.Boards.Delete(ctx, b.ID)
-
-	for _, havingOp := range HavingOps() {
-		q := QuerySpec{
-			Calculations: []CalculationSpec{
-				{
-					Op:     CalculationOpP99,
-					Column: StringPtr("duration_ms"),
-				},
-			},
-			Havings: []HavingSpec{
-				{
-					Column:      StringPtr("duration_ms"),
-					Op:          &havingOp,
-					CalculateOp: CalculationOpPtr(CalculationOpP99),
-					Value:       1000,
-				},
-			},
-		}
-		b.Queries = []BoardQuery{{Dataset: dataset, Query: &q}}
-
-		_, err = c.Boards.Update(ctx, b)
-		assert.NoError(t, err, fmt.Sprintf("Failed to create board that contains having with op \"%v\"", havingOp))
-	}
 }
diff --git a/honeycombio/resource_board_test.go b/honeycombio/resource_board_test.go
index 255db7d..de41997 100644
--- a/honeycombio/resource_board_test.go
+++ b/honeycombio/resource_board_test.go
@@ -82,11 +82,10 @@ resource "honeycombio_board" "test" {
   query {
     caption             = "test query 1"
     query_style         = "combo"
-    dataset             = "%s"
     query_id            = honeycombio_query.test[1].id
     query_annotation_id = honeycombio_query_annotation.test[1].id
   }
-}`, dataset, dataset, dataset, dataset)
+}`, dataset, dataset, dataset)
 }
 
 func testAccCheckBoardExists(t *testing.T, name string) resource.TestCheckFunc {
@@ -102,11 +101,6 @@ func testAccCheckBoardExists(t *testing.T, name string) resource.TestCheckFunc {
 			return fmt.Errorf("could not find created board: %w", err)
 		}
 
-		for i := range createdBoard.Queries {
-			// we don't track the QuerySpec, just the IDs
-			createdBoard.Queries[i].Query = nil
-		}
-
 		expectedBoard := &honeycombio.Board{
 			ID:          createdBoard.ID,
 			Name:        "Test board from terraform-provider-honeycombio",