Skip to content

Commit

Permalink
feat(rs-eventhouse): add configuration support (#224)
Browse files Browse the repository at this point in the history
# 📥 Pull Request

## ❓ What are you trying to address

This pull request introduces several changes to the `fabric_eventhouse`
resource, including the addition of a new configuration attribute and
updates to the documentation and tests.
  • Loading branch information
DariuszPorowski authored Jan 30, 2025
1 parent 7e507a6 commit aef565f
Show file tree
Hide file tree
Showing 12 changed files with 210 additions and 27 deletions.
5 changes: 5 additions & 0 deletions .changes/unreleased/added-20250128-093811.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: added
body: New `configuration` attribute in the `fabric_eventhouse` Resource.
time: 2025-01-28T09:38:11.8439891+01:00
custom:
Issue: "224"
24 changes: 24 additions & 0 deletions docs/resources/eventhouse.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ resource "fabric_eventhouse" "example_definition_bootstrap" {
display_name = "example2"
description = "example with definition bootstrapping"
workspace_id = "00000000-0000-0000-0000-000000000000"
format = "Default"
definition_update_enabled = false # <-- Disable definition update
definition = {
"EventhouseProperties.json" = {
Expand All @@ -43,6 +44,7 @@ resource "fabric_eventhouse" "example_definition_update" {
display_name = "example3"
description = "example with definition update when source or tokens changed"
workspace_id = "00000000-0000-0000-0000-000000000000"
format = "Default"
definition = {
"EventhouseProperties.json" = {
source = "${local.path}/EventhouseProperties.json.tmpl"
Expand All @@ -52,6 +54,16 @@ resource "fabric_eventhouse" "example_definition_update" {
}
}
}
# Example 4 - Item with configuration, no definition - configuration and definition cannot be used together at the same time
resource "fabric_eventhouse" "example_configuration" {
display_name = "example4"
description = "example with configuration"
workspace_id = "00000000-0000-0000-0000-000000000000"
configuration = {
minimum_consumption_units = "2.25"
}
}
```

<!-- schema generated by tfplugindocs -->
Expand All @@ -64,6 +76,10 @@ resource "fabric_eventhouse" "example_definition_update" {

### Optional

- `configuration` (Attributes) The Eventhouse creation configuration.

Any changes to this configuration will result in recreation of the Eventhouse. (see [below for nested schema](#nestedatt--configuration))

- `definition` (Attributes Map) Definition parts. Read more about [Eventhouse definition part paths](https://learn.microsoft.com/rest/api/fabric/articles/item-management/definitions/eventhouse-definition). Accepted path keys: **Default** format: `EventhouseProperties.json` (see [below for nested schema](#nestedatt--definition))
- `definition_update_enabled` (Boolean) Update definition on change of source content. Default: `true`.
- `description` (String) The Eventhouse description.
Expand All @@ -75,6 +91,14 @@ resource "fabric_eventhouse" "example_definition_update" {
- `id` (String) The Eventhouse ID.
- `properties` (Attributes) The Eventhouse properties. (see [below for nested schema](#nestedatt--properties))

<a id="nestedatt--configuration"></a>

### Nested Schema for `configuration`

Required:

- `minimum_consumption_units` (Number) When activated, the eventhouse is always available at the selected minimum level and you pay at least the minimum compute selected. Accepted values: `0`, `13`, `18`, `2.25`, `26`, `34`, `4.25`, `50`, `8.5` or any number between `51` and `322`. For more information, see [minimum consumption](https://learn.microsoft.com/fabric/real-time-intelligence/eventhouse#minimum-consumption)

<a id="nestedatt--definition"></a>

### Nested Schema for `definition`
Expand Down
12 changes: 12 additions & 0 deletions examples/resources/fabric_eventhouse/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ resource "fabric_eventhouse" "example_definition_bootstrap" {
display_name = "example2"
description = "example with definition bootstrapping"
workspace_id = "00000000-0000-0000-0000-000000000000"
format = "Default"
definition_update_enabled = false # <-- Disable definition update
definition = {
"EventhouseProperties.json" = {
Expand All @@ -22,6 +23,7 @@ resource "fabric_eventhouse" "example_definition_update" {
display_name = "example3"
description = "example with definition update when source or tokens changed"
workspace_id = "00000000-0000-0000-0000-000000000000"
format = "Default"
definition = {
"EventhouseProperties.json" = {
source = "${local.path}/EventhouseProperties.json.tmpl"
Expand All @@ -31,3 +33,13 @@ resource "fabric_eventhouse" "example_definition_update" {
}
}
}

# Example 4 - Item with configuration, no definition - configuration and definition cannot be used together at the same time
resource "fabric_eventhouse" "example_configuration" {
display_name = "example4"
description = "example with configuration"
workspace_id = "00000000-0000-0000-0000-000000000000"
configuration = {
minimum_consumption_units = "2.25"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@ var (

type ResourceFabricItemConfigDefinitionProperties[Ttfprop, Titemprop, Ttfconfig, Titemconfig any] struct {
ResourceFabricItemDefinition
IsConfigRequired bool
ConfigAttributes map[string]schema.Attribute
PropertiesAttributes map[string]schema.Attribute
PropertiesSetter func(ctx context.Context, from *Titemprop, to *ResourceFabricItemConfigDefinitionPropertiesModel[Ttfprop, Titemprop, Ttfconfig, Titemconfig]) diag.Diagnostics
CreationPayloadSetter func(ctx context.Context, from Ttfconfig) (*Titemconfig, diag.Diagnostics)
ItemGetter func(ctx context.Context, fabricClient fabric.Client, model ResourceFabricItemConfigDefinitionPropertiesModel[Ttfprop, Titemprop, Ttfconfig, Titemconfig], fabricItem *FabricItemProperties[Titemprop]) error
ConfigRequired bool
ConfigOrDefinitionRequired bool
ConfigAttributes map[string]schema.Attribute
PropertiesAttributes map[string]schema.Attribute
PropertiesSetter func(ctx context.Context, from *Titemprop, to *ResourceFabricItemConfigDefinitionPropertiesModel[Ttfprop, Titemprop, Ttfconfig, Titemconfig]) diag.Diagnostics
CreationPayloadSetter func(ctx context.Context, from Ttfconfig) (*Titemconfig, diag.Diagnostics)
ItemGetter func(ctx context.Context, fabricClient fabric.Client, model ResourceFabricItemConfigDefinitionPropertiesModel[Ttfprop, Titemprop, Ttfconfig, Titemconfig], fabricItem *FabricItemProperties[Titemprop]) error
}

func NewResourceFabricItemConfigDefinitionProperties[Ttfprop, Titemprop, Ttfconfig, Titemconfig any](config ResourceFabricItemConfigDefinitionProperties[Ttfprop, Titemprop, Ttfconfig, Titemconfig]) resource.Resource {
Expand Down Expand Up @@ -97,16 +98,21 @@ func (r *ResourceFabricItemConfigDefinitionProperties[Ttfprop, Titemprop, Ttfcon
}

func (r *ResourceFabricItemConfigDefinitionProperties[Ttfprop, Titemprop, Ttfconfig, Titemconfig]) ConfigValidators(_ context.Context) []resource.ConfigValidator { //revive:disable-line:confusing-naming
return []resource.ConfigValidator{
resourcevalidator.Conflicting(
path.MatchRoot("configuration"),
path.MatchRoot("definition"),
),
resourcevalidator.ExactlyOneOf(
result := []resource.ConfigValidator{}

if r.ConfigOrDefinitionRequired {
result = append(result, resourcevalidator.ExactlyOneOf(
path.MatchRoot("configuration"),
path.MatchRoot("definition"),
),
))
}

result = append(result, resourcevalidator.Conflicting(
path.MatchRoot("configuration"),
path.MatchRoot("definition"),
))

return result
}

func (r *ResourceFabricItemConfigDefinitionProperties[Ttfprop, Titemprop, Ttfconfig, Titemconfig]) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { //revive:disable-line:confusing-naming
Expand Down
2 changes: 1 addition & 1 deletion internal/pkg/fabricitem/resource_item_config_properties.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var (

type ResourceFabricItemConfigProperties[Ttfprop, Titemprop, Ttfconfig, Titemconfig any] struct {
ResourceFabricItem
IsConfigRequired bool
ConfigRequired bool
ConfigAttributes map[string]schema.Attribute
PropertiesAttributes map[string]schema.Attribute
PropertiesSetter func(ctx context.Context, from *Titemprop, to *ResourceFabricItemConfigPropertiesModel[Ttfprop, Titemprop, Ttfconfig, Titemconfig]) diag.Diagnostics
Expand Down
4 changes: 2 additions & 2 deletions internal/pkg/fabricitem/resource_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func getResourceFabricItemDefinitionPropertiesSchema[Ttfprop, Titemprop any](ctx

func getResourceFabricItemConfigPropertiesSchema[Ttfprop, Titemprop, Ttfconfig, Titemconfig any](ctx context.Context, r ResourceFabricItemConfigProperties[Ttfprop, Titemprop, Ttfconfig, Titemconfig]) schema.Schema {
attributes := getResourceFabricItemBaseAttributes(ctx, r.Name, r.DisplayNameMaxLength, r.DescriptionMaxLength, r.NameRenameAllowed)
attributes["configuration"] = getResourceFabricItemConfigNestedAttr[Ttfconfig](ctx, r.Name, r.IsConfigRequired, r.ConfigAttributes)
attributes["configuration"] = getResourceFabricItemConfigNestedAttr[Ttfconfig](ctx, r.Name, r.ConfigRequired, r.ConfigAttributes)
attributes["properties"] = getResourceFabricItemPropertiesNestedAttr[Ttfprop](ctx, r.Name, r.PropertiesAttributes)

return schema.Schema{
Expand All @@ -88,7 +88,7 @@ func getResourceFabricItemConfigPropertiesSchema[Ttfprop, Titemprop, Ttfconfig,

func getResourceFabricItemConfigDefinitionPropertiesSchema[Ttfprop, Titemprop, Ttfconfig, Titemconfig any](ctx context.Context, r ResourceFabricItemConfigDefinitionProperties[Ttfprop, Titemprop, Ttfconfig, Titemconfig]) schema.Schema {
attributes := getResourceFabricItemBaseAttributes(ctx, r.Name, r.DisplayNameMaxLength, r.DescriptionMaxLength, r.NameRenameAllowed)
attrConfiguration := getResourceFabricItemConfigNestedAttr[Ttfconfig](ctx, r.Name, r.IsConfigRequired, r.ConfigAttributes)
attrConfiguration := getResourceFabricItemConfigNestedAttr[Ttfconfig](ctx, r.Name, r.ConfigRequired, r.ConfigAttributes)
attrConfiguration.Validators = []validator.Object{
objectvalidator.ConflictsWith(
path.MatchRoot("definition"),
Expand Down
12 changes: 12 additions & 0 deletions internal/services/eventhouse/models_resource_eventhouse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MPL-2.0

package eventhouse

import (
"github.com/hashicorp/terraform-plugin-framework/types"
)

type eventhouseConfigurationModel struct {
MinimumConsumptionUnits types.Float64 `tfsdk:"minimum_consumption_units"`
}
31 changes: 22 additions & 9 deletions internal/services/eventhouse/resource_eventhouse.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,24 @@ import (
)

func NewResourceEventhouse(ctx context.Context) resource.Resource {
propertiesSetter := func(ctx context.Context, from *fabeventhouse.Properties, to *fabricitem.ResourceFabricItemDefinitionPropertiesModel[eventhousePropertiesModel, fabeventhouse.Properties]) diag.Diagnostics {
creationPayloadSetter := func(_ context.Context, from eventhouseConfigurationModel) (*fabeventhouse.CreationPayload, diag.Diagnostics) {
creationPayload := fabeventhouse.CreationPayload{}

if !from.MinimumConsumptionUnits.IsNull() && !from.MinimumConsumptionUnits.IsUnknown() {
creationPayload.MinimumConsumptionUnits = from.MinimumConsumptionUnits.ValueFloat64Pointer()
}

return &creationPayload, nil
}

propertiesSetter := func(ctx context.Context, from *fabeventhouse.Properties, to *fabricitem.ResourceFabricItemConfigDefinitionPropertiesModel[eventhousePropertiesModel, fabeventhouse.Properties, eventhouseConfigurationModel, fabeventhouse.CreationPayload]) diag.Diagnostics {
properties := supertypes.NewSingleNestedObjectValueOfNull[eventhousePropertiesModel](ctx)

if from != nil {
propertiesModel := &eventhousePropertiesModel{}
propertiesModel.set(ctx, from)

diags := properties.Set(ctx, propertiesModel)
if diags.HasError() {
if diags := properties.Set(ctx, propertiesModel); diags.HasError() {
return diags
}
}
Expand All @@ -36,7 +45,7 @@ func NewResourceEventhouse(ctx context.Context) resource.Resource {
return nil
}

itemGetter := func(ctx context.Context, fabricClient fabric.Client, model fabricitem.ResourceFabricItemDefinitionPropertiesModel[eventhousePropertiesModel, fabeventhouse.Properties], fabricItem *fabricitem.FabricItemProperties[fabeventhouse.Properties]) error {
itemGetter := func(ctx context.Context, fabricClient fabric.Client, model fabricitem.ResourceFabricItemConfigDefinitionPropertiesModel[eventhousePropertiesModel, fabeventhouse.Properties, eventhouseConfigurationModel, fabeventhouse.CreationPayload], fabricItem *fabricitem.FabricItemProperties[fabeventhouse.Properties]) error {
client := fabeventhouse.NewClientFactoryWithClient(fabricClient).NewItemsClient()

respGet, err := client.GetEventhouse(ctx, model.WorkspaceID.ValueString(), model.ID.ValueString(), nil)
Expand All @@ -49,7 +58,7 @@ func NewResourceEventhouse(ctx context.Context) resource.Resource {
return nil
}

config := fabricitem.ResourceFabricItemDefinitionProperties[eventhousePropertiesModel, fabeventhouse.Properties]{
config := fabricitem.ResourceFabricItemConfigDefinitionProperties[eventhousePropertiesModel, fabeventhouse.Properties, eventhouseConfigurationModel, fabeventhouse.CreationPayload]{
ResourceFabricItemDefinition: fabricitem.ResourceFabricItemDefinition{
Type: ItemType,
Name: ItemName,
Expand All @@ -69,10 +78,14 @@ func NewResourceEventhouse(ctx context.Context) resource.Resource {
DefinitionEmpty: ItemDefinitionEmpty,
DefinitionFormats: itemDefinitionFormats,
},
PropertiesAttributes: getResourceEventhousePropertiesAttributes(ctx),
PropertiesSetter: propertiesSetter,
ItemGetter: itemGetter,
ConfigRequired: false,
ConfigOrDefinitionRequired: false,
ConfigAttributes: getResourceEventhouseConfigurationAttributes(),
CreationPayloadSetter: creationPayloadSetter,
PropertiesAttributes: getResourceEventhousePropertiesAttributes(ctx),
PropertiesSetter: propertiesSetter,
ItemGetter: itemGetter,
}

return fabricitem.NewResourceFabricItemDefinitionProperties(config)
return fabricitem.NewResourceFabricItemConfigDefinitionProperties(config)
}
82 changes: 82 additions & 0 deletions internal/services/eventhouse/resource_eventhouse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,24 @@ func TestUnit_EventhouseResource_Attributes(t *testing.T) {
)),
ExpectError: regexp.MustCompile(`The argument "display_name" is required, but no definition was found.`),
},
// error - no required attributes
{
ResourceName: testResourceItemFQN,
Config: at.JoinConfigs(
testHelperLocals,
at.CompileConfig(
testResourceItemHeader,
map[string]any{
"display_name": "test",
"workspace_id": "00000000-0000-0000-0000-000000000000",
"definition": testHelperDefinition,
"configuration": map[string]any{
"minimum_consumption_units": "2.25",
},
},
)),
ExpectError: regexp.MustCompile(`Invalid Attribute Combination`),
},
}))
}

Expand Down Expand Up @@ -372,3 +390,67 @@ func TestAcc_EventhouseDefinitionResource_CRUD(t *testing.T) {
},
))
}

func TestAcc_EventhouseConfigurationResource_CRUD(t *testing.T) {
workspace := testhelp.WellKnown()["WorkspaceRS"].(map[string]any)
workspaceID := workspace["id"].(string)

entityCreateDisplayName := testhelp.RandomName()
entityUpdateDisplayName := testhelp.RandomName()
entityUpdateDescription := testhelp.RandomName()

resource.Test(t, testhelp.NewTestAccCase(t, &testResourceItemFQN, nil, []resource.TestStep{
// Create and Read
{
ResourceName: testResourceItemFQN,
Config: at.JoinConfigs(
testHelperLocals,
at.CompileConfig(
testResourceItemHeader,
map[string]any{
"workspace_id": workspaceID,
"display_name": entityCreateDisplayName,
"configuration": map[string]any{
"minimum_consumption_units": "2.25",
},
},
)),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(testResourceItemFQN, "display_name", entityCreateDisplayName),
resource.TestCheckResourceAttr(testResourceItemFQN, "description", ""),
resource.TestCheckResourceAttr(testResourceItemFQN, "definition_update_enabled", "true"),
resource.TestCheckResourceAttrSet(testResourceItemFQN, "properties.query_service_uri"),
resource.TestCheckResourceAttrSet(testResourceItemFQN, "properties.ingestion_service_uri"),
resource.TestCheckResourceAttrSet(testResourceItemFQN, "properties.database_ids.0"),
resource.TestCheckResourceAttr(testResourceItemFQN, "configuration.minimum_consumption_units", "2.25"),
),
},
// Update and Read
{
ResourceName: testResourceItemFQN,
Config: at.JoinConfigs(
testHelperLocals,
at.CompileConfig(
testResourceItemHeader,
map[string]any{
"workspace_id": workspaceID,
"display_name": entityUpdateDisplayName,
"description": entityUpdateDescription,
"configuration": map[string]any{
"minimum_consumption_units": "2.25",
},
},
)),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(testResourceItemFQN, "display_name", entityUpdateDisplayName),
resource.TestCheckResourceAttr(testResourceItemFQN, "description", entityUpdateDescription),
resource.TestCheckResourceAttr(testResourceItemFQN, "definition_update_enabled", "true"),
resource.TestCheckResourceAttrSet(testResourceItemFQN, "properties.query_service_uri"),
resource.TestCheckResourceAttrSet(testResourceItemFQN, "properties.ingestion_service_uri"),
resource.TestCheckResourceAttrSet(testResourceItemFQN, "properties.database_ids.0"),
resource.TestCheckResourceAttr(testResourceItemFQN, "configuration.minimum_consumption_units", "2.25"),
),
},
},
))
}
29 changes: 29 additions & 0 deletions internal/services/eventhouse/schema_resource_eventhouse.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,16 @@ package eventhouse

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework-validators/float64validator"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/float64planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
supertypes "github.com/orange-cloudavenue/terraform-plugin-framework-supertypes"

"github.com/microsoft/terraform-provider-fabric/internal/pkg/utils"
)

func getResourceEventhousePropertiesAttributes(ctx context.Context) map[string]schema.Attribute {
Expand All @@ -29,3 +36,25 @@ func getResourceEventhousePropertiesAttributes(ctx context.Context) map[string]s

return result
}

func getResourceEventhouseConfigurationAttributes() map[string]schema.Attribute {
possibleMinimumConsumptionUnitsValues := []float64{0, 2.25, 4.25, 8.5, 13, 18, 26, 34, 50}
customMin := float64(51)
customMax := float64(322)

return map[string]schema.Attribute{
"minimum_consumption_units": schema.Float64Attribute{
MarkdownDescription: "When activated, the eventhouse is always available at the selected minimum level and you pay at least the minimum compute selected. Accepted values: " + utils.ConvertStringSlicesToString(possibleMinimumConsumptionUnitsValues, true, true) + " or any number between `" + fmt.Sprintf("%v", customMin) + "` and `" + fmt.Sprintf("%v", customMax) + "`. For more information, see [minimum consumption](https://learn.microsoft.com/fabric/real-time-intelligence/eventhouse#minimum-consumption)",
Required: true,
Validators: []validator.Float64{
float64validator.Any(
float64validator.OneOf(possibleMinimumConsumptionUnitsValues...),
float64validator.Between(customMin, customMax),
),
},
PlanModifiers: []planmodifier.Float64{
float64planmodifier.RequiresReplace(),
},
},
}
}
2 changes: 1 addition & 1 deletion internal/services/kqldatabase/resource_kql_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func NewResourceKQLDatabase() resource.Resource {
// DefinitionRequired: false,
// DefinitionEmpty: "",
},
IsConfigRequired: true,
ConfigRequired: true,
ConfigAttributes: getResourceKQLDatabaseConfigurationAttributes(),
CreationPayloadSetter: creationPayloadSetter,
PropertiesAttributes: getResourceKQLDatabasePropertiesAttributes(),
Expand Down
Loading

0 comments on commit aef565f

Please sign in to comment.