Skip to content

Commit

Permalink
r/board: add SLO support
Browse files Browse the repository at this point in the history
  • Loading branch information
jharley committed Jun 13, 2024
1 parent 92f7561 commit 4f240c9
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 2 deletions.
2 changes: 2 additions & 0 deletions client/board.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ type Board struct {
Links BoardLinks `json:"links,omitempty"`
// A list of queries displayed on the board, in order of appearance.
Queries []BoardQuery `json:"queries"`
// A list of SLO IDs to be added to the board
SLOs []string `json:"slos"`
}

// BoardStyle determines how a Board should be displayed within the Honeycomb UI.
Expand Down
20 changes: 20 additions & 0 deletions client/board_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,24 @@ func TestBoards(t *testing.T) {
})
require.NoError(t, err)

sli, err := c.DerivedColumns.Create(ctx, dataset, &client.DerivedColumn{
Alias: test.RandomStringWithPrefix("test.", 8),
Expression: "BOOL(1)",
})
require.NoError(t, err)
slo, err := c.SLOs.Create(ctx, dataset, &client.SLO{
Name: test.RandomStringWithPrefix("test.", 8),
TimePeriodDays: 7,
TargetPerMillion: 990000,
SLI: client.SLIRef{Alias: sli.Alias},
})
require.NoError(t, err)
t.Cleanup(func() {
//nolint:errcheck
c.SLOs.Delete(ctx, dataset, slo.ID)
c.DerivedColumns.Delete(ctx, dataset, sli.ID)
})

t.Run("Create", func(t *testing.T) {
data := &client.Board{
Name: test.RandomStringWithPrefix("test.", 8),
Expand All @@ -57,6 +75,7 @@ func TestBoards(t *testing.T) {
GraphSettings: client.BoardGraphSettings{OmitMissingValues: true, UseUTCXAxis: true},
},
},
SLOs: []string{slo.ID},
}
b, err = c.Boards.Create(ctx, data)
require.NoError(t, err)
Expand Down Expand Up @@ -104,6 +123,7 @@ func TestBoards(t *testing.T) {
QueryID: *newQuery.ID,
GraphSettings: client.BoardGraphSettings{UseUTCXAxis: true},
})
b.SLOs = []string{}

result, err := c.Boards.Update(ctx, b)
require.NoError(t, err)
Expand Down
7 changes: 6 additions & 1 deletion docs/resources/board.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,9 @@ The following arguments are supported:
* `column_layout` - (Optional) the number of columns to layout on the board, either `multi` (the default) or `single`. Only `visual` style boards (see below) have a column layout.
* `style` - (Optional) Deprecated: All Boards are now displayed as `visual` style. How the board should be displayed in the UI, either `visual` (the default) or `list`.
* `query` - (Optional) Zero or more configurations blocks (described below) with the queries of the board.
* `slo` - (Optional) Up to six configuration blocks (described below) to place SLOs on the board.

Each board configuration may have zero or more `query` blocks, which accepts the following arguments:
Each board configuration may have zero or more `query` blocks, which accept the following arguments:

* `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.
Expand All @@ -120,6 +121,10 @@ Currently supported toggles are:
See [Graph Settings](https://docs.honeycomb.io/working-with-your-data/graph-settings/) in the documentation for more information on any individual setting.
* `query_style` - (Optional) How the query should be displayed within the board, either `graph` (the default), `table` or `combo`.

Each board configuration may have up to six `slo` blocks, which take the following arguments:

* `id` - (Required) The ID of the SLO to place on the board.

## Attribute Reference

In addition to all arguments above, the following attributes are exported:
Expand Down
31 changes: 30 additions & 1 deletion honeycombio/resource_board.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,21 @@ See [Graph Settings](https://docs.honeycomb.io/working-with-your-data/graph-sett
},
},
},
"slo": {
Type: schema.TypeSet,
Optional: true,
Description: "An SLO to added to the board.",
MaxItems: 6,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Required: true,
Description: "The ID of the SLO.",
},
},
},
},
},
}
}
Expand Down Expand Up @@ -200,9 +215,16 @@ func resourceBoardRead(ctx context.Context, d *schema.ResourceData, meta interfa
"query_annotation_id": q.QueryAnnotationID,
}
}

d.Set("query", queries)

slos := make([]map[string]interface{}, len(b.SLOs))
for i, s := range b.SLOs {
slos[i] = map[string]interface{}{
"id": s,
}
}
d.Set("slo", slos)

return nil
}

Expand Down Expand Up @@ -258,13 +280,20 @@ func expandBoard(d *schema.ResourceData) (*honeycombio.Board, error) {
})
}

slos := []string{}
// Board SLOs don't currently have an order: the API returns them sorted by creation time
for _, s := range d.Get("slo").(*schema.Set).List() {
slos = append(slos, s.(map[string]interface{})["id"].(string))
}

board := &honeycombio.Board{
ID: d.Id(),
Name: d.Get("name").(string),
Description: d.Get("description").(string),
Style: honeycombio.BoardStyle(d.Get("style").(string)),
ColumnLayout: honeycombio.BoardColumnStyle(d.Get("column_layout").(string)),
Queries: queries,
SLOs: slos,
}

if board.Style == honeycombio.BoardStyleList && board.ColumnLayout != "" {
Expand Down
144 changes: 144 additions & 0 deletions honeycombio/resource_board_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import (

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/stretchr/testify/require"

"github.com/honeycombio/terraform-provider-honeycombio/client"
)

func TestAccHoneycombioBoard_basic(t *testing.T) {
Expand Down Expand Up @@ -183,6 +187,146 @@ resource "honeycombio_board" "test" {
})
}

func TestAccBoard_withSLOs(t *testing.T) {
ctx := context.Background()
dataset := testAccDataset()
c := testAccClient(t)

sli1, err := c.DerivedColumns.Create(ctx, dataset, &client.DerivedColumn{
Alias: "sli." + acctest.RandString(8),
Expression: "BOOL(1)",
})
require.NoError(t, err)
slo1, err := c.SLOs.Create(ctx, dataset, &client.SLO{
Name: acctest.RandString(8) + " SLO",
TimePeriodDays: 14,
TargetPerMillion: 995000,
SLI: client.SLIRef{Alias: sli1.Alias},
})
require.NoError(t, err)

sli2, err := c.DerivedColumns.Create(ctx, dataset, &client.DerivedColumn{
Alias: "sli." + acctest.RandString(8),
Expression: "BOOL(1)",
})
require.NoError(t, err)
slo2, err := c.SLOs.Create(ctx, dataset, &client.SLO{
Name: acctest.RandString(8) + " SLO",
TimePeriodDays: 14,
TargetPerMillion: 995000,
SLI: client.SLIRef{Alias: sli2.Alias},
})
require.NoError(t, err)

//nolint:errcheck
t.Cleanup(func() {
// remove SLOs, and SLIs at end of test run
c.SLOs.Delete(ctx, dataset, slo1.ID)
c.SLOs.Delete(ctx, dataset, slo2.ID)
c.DerivedColumns.Delete(ctx, dataset, sli1.ID)
c.DerivedColumns.Delete(ctx, dataset, sli2.ID)
})

resource.Test(t, resource.TestCase{
PreCheck: testAccPreCheck(t),
ProtoV5ProviderFactories: testAccProtoV5ProviderFactory,
Steps: []resource.TestStep{
// create a board with one SLO on it
{
Config: fmt.Sprintf(`
data "honeycombio_query_specification" "test" {
calculation {
op = "COUNT"
}
}
resource "honeycombio_query" "test" {
dataset = "%s"
query_json = data.honeycombio_query_specification.test.json
}
resource "honeycombio_board" "test" {
name = "board with some SLOs"
query {
query_id = honeycombio_query.test.id
}
slo {
id = "%s"
}
}
`, dataset, slo1.ID),
Check: resource.ComposeTestCheckFunc(
testAccCheckBoardExists(t, "honeycombio_board.test"),
resource.TestCheckResourceAttr("honeycombio_board.test", "slo.#", "1"),
resource.TestCheckResourceAttr("honeycombio_board.test", "slo.0.id", slo1.ID),
),
},
{
// update that board to have two SLOs
Config: fmt.Sprintf(`
data "honeycombio_query_specification" "test" {
calculation {
op = "COUNT"
}
}
resource "honeycombio_query" "test" {
dataset = "%s"
query_json = data.honeycombio_query_specification.test.json
}
resource "honeycombio_board" "test" {
name = "board with some SLOs"
query {
query_id = honeycombio_query.test.id
}
slo {
id = "%s"
}
slo {
id = "%s"
}
}`, dataset, slo2.ID, slo1.ID),
Check: resource.ComposeTestCheckFunc(
testAccCheckBoardExists(t, "honeycombio_board.test"),
resource.TestCheckResourceAttr("honeycombio_board.test", "slo.#", "2"),
),
},
{
// remove all SLOs from that board
Config: fmt.Sprintf(`
data "honeycombio_query_specification" "test" {
calculation {
op = "COUNT"
}
}
resource "honeycombio_query" "test" {
dataset = "%s"
query_json = data.honeycombio_query_specification.test.json
}
resource "honeycombio_board" "test" {
name = "board with no SLOs"
query {
query_id = honeycombio_query.test.id
}
}`, dataset),
Check: resource.ComposeTestCheckFunc(
testAccCheckBoardExists(t, "honeycombio_board.test"),
resource.TestCheckResourceAttr("honeycombio_board.test", "slo.#", "0"),
),
},
},
})
}

func testAccBoardConfig(dataset string) string {
return fmt.Sprintf(`
data "honeycombio_query_specification" "test" {
Expand Down

0 comments on commit 4f240c9

Please sign in to comment.