Skip to content

Commit

Permalink
fix: correctly handle different input/output types
Browse files Browse the repository at this point in the history
  • Loading branch information
henryde committed May 21, 2024
1 parent c9ee90c commit ca9084a
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 15 deletions.
6 changes: 3 additions & 3 deletions internal/provider/buildingblock.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ type MeshBuildingBlockSpec struct {
}

type MeshBuildingBlockIO struct {
Key string `json:"key" tfsdk:"key"`
Value string `json:"value" tfsdk:"value"`
ValueType string `json:"valueType" tfsdk:"value_type"`
Key string `json:"key" tfsdk:"key"`
Value interface{} `json:"value" tfsdk:"value"`
ValueType string `json:"valueType" tfsdk:"value_type"`
}

type MeshBuildingBlockParent struct {
Expand Down
64 changes: 59 additions & 5 deletions internal/provider/buildingblock_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)

// Ensure provider defined types fully satisfy framework interfaces.
Expand All @@ -30,15 +31,18 @@ func (d *buildingBlockDataSource) Metadata(ctx context.Context, req datasource.M
}

func (d *buildingBlockDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
// Dynamic attributes are not supported as nested attributes, we use mutually exclusive fields for each possible value type instead.
mkIoList := func(desc string) schema.ListNestedAttribute {
return schema.ListNestedAttribute{
Computed: true,
MarkdownDescription: desc,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"key": schema.StringAttribute{Computed: true},
"value": schema.StringAttribute{Computed: true},
"value_type": schema.StringAttribute{Computed: true},
"key": schema.StringAttribute{Computed: true},
"value_string": schema.StringAttribute{Computed: true},
"value_int": schema.Int64Attribute{Computed: true},
"value_bool": schema.BoolAttribute{Computed: true},
"value_type": schema.StringAttribute{Computed: true},
},
},
}
Expand Down Expand Up @@ -137,6 +141,43 @@ func (d *buildingBlockDataSource) Configure(ctx context.Context, req datasource.
}

func (d *buildingBlockDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
type io struct {
Key types.String `tfsdk:"key"`
ValueString types.String `tfsdk:"value_string"`
ValueInt types.Int64 `tfsdk:"value_int"`
ValueBool types.Bool `tfsdk:"value_bool"`
ValueType types.String `tfsdk:"value_type"`
}

mkIoList := func(ios *[]MeshBuildingBlockIO) *[]io {
result := make([]io, 0)
for _, input := range *ios {
var valueString *string
var valueInt *int64
var valueBool *bool

if input.ValueType == "STRING" {
val := input.Value.(string)
valueString = &val
} else if input.ValueType == "INTEGER" {
val := int64(input.Value.(float64))
valueInt = &val
} else if input.ValueType == "BOOLEAN" {
val := input.Value.(bool)
valueBool = &val
}

result = append(result, io{
Key: types.StringValue(input.Key),
ValueString: types.StringPointerValue(valueString),
ValueInt: types.Int64PointerValue(valueInt),
ValueBool: types.BoolPointerValue(valueBool),
ValueType: types.StringValue(input.ValueType),
})
}
return &result
}

// get UUID for BB we want to query from the request
var uuid string
resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("metadata").AtName("uuid"), &uuid)...)
Expand All @@ -145,6 +186,19 @@ func (d *buildingBlockDataSource) Read(ctx context.Context, req datasource.ReadR
resp.Diagnostics.AddError("Unable to read buildingblock", err.Error())
}

// client data maps directly to the schema so we just need to set the state
resp.Diagnostics.Append(resp.State.Set(ctx, bb)...)
// must set attributes individually to handle dynamic input/output types
resp.State.SetAttribute(ctx, path.Root("api_version"), bb.ApiVersion)
resp.State.SetAttribute(ctx, path.Root("kind"), bb.Kind)
resp.State.SetAttribute(ctx, path.Root("metadata"), bb.Metadata)

resp.State.SetAttribute(ctx, path.Root("spec").AtName("display_name"), bb.Spec.DisplayName)
resp.State.SetAttribute(ctx, path.Root("spec").AtName("parent_building_blocks"), bb.Spec.ParentBuildingBlocks)
if bb.Spec.Inputs != nil {
resp.State.SetAttribute(ctx, path.Root("spec").AtName("inputs"), mkIoList(&bb.Spec.Inputs))
}

resp.State.SetAttribute(ctx, path.Root("status").AtName("status"), bb.Status.Status)
if bb.Status.Outputs != nil {
resp.State.SetAttribute(ctx, path.Root("status").AtName("outputs"), &bb.Status.Outputs)
}
}
12 changes: 5 additions & 7 deletions internal/provider/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,12 @@ func (c *MeshStackProviderClient) ReadBuildingBlock(uuid string) (*MeshBuildingB
}

targetPath := c.endpoints.BuildingBlocks.JoinPath(uuid)
req, err := http.NewRequest("GET", targetPath.String(), nil)
if err != nil {
return nil, err
}

res, err := c.doAuthenticatedRequest(&http.Request{
URL: targetPath,
Method: "GET",
},
)

res, err := c.doAuthenticatedRequest(req)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -283,7 +282,6 @@ func (c *MeshStackProviderClient) CreateProject(project *MeshProjectCreate) (*Me
return nil, err
}

// TODO: create will also succeed if the project already exists
if res.StatusCode != 201 {
return nil, errors.New(fmt.Sprintf("unexpected status code: %d, %s", res.StatusCode, data))
}
Expand Down

0 comments on commit ca9084a

Please sign in to comment.