Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update tfsdk helpers to use *diags #855

Merged
merged 7 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- Support updating `elasticstack_elasticsearch_security_api_key` when supported by the backing cluster ([#843](https://github.com/elastic/terraform-provider-elasticstack/pull/843))
- Fix validation of `throttle`, and `interval` attributes in `elasticstack_kibana_alerting_rule` allowing all Elastic duration values ([#846](https://github.com/elastic/terraform-provider-elasticstack/pull/846))
- Fix boolean setting parsing for `elasticstack_elasticsearch_indices` data source. ([#842](https://github.com/elastic/terraform-provider-elasticstack/pull/842))
- Update all Fleet and utils/tfsdk instances of diagnostics parameters to pass by pointer instead of pass by value. Added upgrader for fleet_integration_policy v0 to handle empty string vars_json/streams_json. ([#855](https://github.com/elastic/terraform-provider-elasticstack/pull/855))

## [0.11.9] - 2024-10-14

Expand Down
2 changes: 1 addition & 1 deletion internal/fleet/enrollment_tokens/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type enrollmentTokenModel struct {
}

func (model *enrollmentTokensModel) populateFromAPI(ctx context.Context, data []fleetapi.EnrollmentApiKey) (diags diag.Diagnostics) {
model.Tokens = utils.SliceToListType(ctx, data, getTokenType(), path.Root("tokens"), diags, newEnrollmentTokenModel)
model.Tokens = utils.SliceToListType(ctx, data, getTokenType(), path.Root("tokens"), &diags, newEnrollmentTokenModel)
return
}

Expand Down
4 changes: 2 additions & 2 deletions internal/fleet/integration/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import (
)

func (r *integrationResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
r.create(ctx, req.Plan, &resp.State, resp.Diagnostics)
r.create(ctx, req.Plan, &resp.State, &resp.Diagnostics)
}

func (r integrationResource) create(ctx context.Context, plan tfsdk.Plan, state *tfsdk.State, respDiags diag.Diagnostics) {
func (r integrationResource) create(ctx context.Context, plan tfsdk.Plan, state *tfsdk.State, respDiags *diag.Diagnostics) {
var planModel integrationModel

diags := plan.Get(ctx, &planModel)
Expand Down
2 changes: 1 addition & 1 deletion internal/fleet/integration/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ import (
)

func (r *integrationResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
r.create(ctx, req.Plan, &resp.State, resp.Diagnostics)
r.create(ctx, req.Plan, &resp.State, &resp.Diagnostics)
}
19 changes: 10 additions & 9 deletions internal/fleet/integration_policy/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ func (model *integrationPolicyModel) populateFromAPI(ctx context.Context, data *
model.Enabled = types.BoolPointerValue(data.Enabled)
model.IntegrationName = types.StringValue(data.Package.Name)
model.IntegrationVersion = types.StringValue(data.Package.Version)
model.VarsJson = utils.MapToNormalizedType(utils.Deref(data.Vars), path.Root("vars_json"), diags)
model.VarsJson = utils.MapToNormalizedType(utils.Deref(data.Vars), path.Root("vars_json"), &diags)

model.populateInputFromAPI(ctx, data.Inputs, diags)
model.populateInputFromAPI(ctx, data.Inputs, &diags)

return diags
}

func (model *integrationPolicyModel) populateInputFromAPI(ctx context.Context, inputs map[string]fleetapi.PackagePolicyInput, diags diag.Diagnostics) {
func (model *integrationPolicyModel) populateInputFromAPI(ctx context.Context, inputs map[string]fleetapi.PackagePolicyInput, diags *diag.Diagnostics) {
newInputs := utils.TransformMapToSlice(inputs, path.Root("input"), diags,
func(inputData fleetapi.PackagePolicyInput, meta utils.MapMeta) integrationPolicyInputModel {
return integrationPolicyInputModel{
Expand All @@ -68,12 +68,13 @@ func (model *integrationPolicyModel) populateInputFromAPI(ctx context.Context, i
}
})
if newInputs == nil {
model.Input = types.ListNull(getInputType())
model.Input = types.ListNull(getInputTypeV1())
} else {
oldInputs := utils.ListTypeAs[integrationPolicyInputModel](ctx, model.Input, path.Root("input"), diags)

sortInputs(newInputs, oldInputs)

inputList, d := types.ListValueFrom(ctx, getInputType(), newInputs)
inputList, d := types.ListValueFrom(ctx, getInputTypeV1(), newInputs)
diags.Append(d...)

model.Input = inputList
Expand All @@ -96,19 +97,19 @@ func (model integrationPolicyModel) toAPIModel(ctx context.Context, isUpdate boo
Version: model.IntegrationVersion.ValueString(),
},
PolicyId: model.AgentPolicyID.ValueString(),
Vars: utils.MapRef(utils.NormalizedTypeToMap[any](model.VarsJson, path.Root("vars_json"), diags)),
Vars: utils.MapRef(utils.NormalizedTypeToMap[any](model.VarsJson, path.Root("vars_json"), &diags)),
}

if isUpdate {
body.Id = model.ID.ValueStringPointer()
}

body.Inputs = utils.MapRef(utils.ListTypeToMap(ctx, model.Input, path.Root("input"), diags,
body.Inputs = utils.MapRef(utils.ListTypeToMap(ctx, model.Input, path.Root("input"), &diags,
func(inputModel integrationPolicyInputModel, meta utils.ListMeta) (string, fleetapi.PackagePolicyRequestInput) {
return inputModel.InputID.ValueString(), fleetapi.PackagePolicyRequestInput{
Enabled: inputModel.Enabled.ValueBoolPointer(),
Streams: utils.MapRef(utils.NormalizedTypeToMap[fleetapi.PackagePolicyRequestInputStream](inputModel.StreamsJson, meta.Path.AtName("streams_json"), diags)),
Vars: utils.MapRef(utils.NormalizedTypeToMap[any](inputModel.VarsJson, meta.Path.AtName("vars_json"), diags)),
Streams: utils.MapRef(utils.NormalizedTypeToMap[fleetapi.PackagePolicyRequestInputStream](inputModel.StreamsJson, meta.Path.AtName("streams_json"), &diags)),
Vars: utils.MapRef(utils.NormalizedTypeToMap[any](inputModel.VarsJson, meta.Path.AtName("vars_json"), &diags)),
}
}))

Expand Down
13 changes: 10 additions & 3 deletions internal/fleet/integration_policy/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import (
)

var (
_ resource.Resource = &integrationPolicyResource{}
_ resource.ResourceWithConfigure = &integrationPolicyResource{}
_ resource.ResourceWithImportState = &integrationPolicyResource{}
_ resource.Resource = &integrationPolicyResource{}
_ resource.ResourceWithConfigure = &integrationPolicyResource{}
_ resource.ResourceWithImportState = &integrationPolicyResource{}
_ resource.ResourceWithUpgradeState = &integrationPolicyResource{}
)

// NewResource is a helper function to simplify the provider implementation.
Expand All @@ -37,3 +38,9 @@ func (r *integrationPolicyResource) Metadata(ctx context.Context, req resource.M
func (r *integrationPolicyResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("policy_id"), req, resp)
}

func (r *integrationPolicyResource) UpgradeState(context.Context) map[int64]resource.StateUpgrader {
return map[int64]resource.StateUpgrader{
0: {PriorSchema: getSchemaV0(), StateUpgrader: upgradeV0},
}
}
9 changes: 5 additions & 4 deletions internal/fleet/integration_policy/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ import (
)

func (r *integrationPolicyResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = getSchema()
resp.Schema = getSchemaV1()
}

func getSchema() schema.Schema {
func getSchemaV1() schema.Schema {
return schema.Schema{
Version: 1,
Description: "Creates a new Fleet Integration Policy. See https://www.elastic.co/guide/en/fleet/current/add-integration-to-policy.html",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Expand Down Expand Up @@ -114,6 +115,6 @@ func getSchema() schema.Schema {
}
}

func getInputType() attr.Type {
return getSchema().Blocks["input"].Type().(attr.TypeWithElementType).ElementType()
func getInputTypeV1() attr.Type {
return getSchemaV1().Blocks["input"].Type().(attr.TypeWithElementType).ElementType()
}
114 changes: 114 additions & 0 deletions internal/fleet/integration_policy/upgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package integration_policy

import (
"context"

"github.com/elastic/terraform-provider-elasticstack/internal/utils"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
)

func getSchemaV0() *schema.Schema {
return &schema.Schema{
Version: 0,
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
"policy_id": schema.StringAttribute{Computed: true, Optional: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace(), stringplanmodifier.UseStateForUnknown()}},
"name": schema.StringAttribute{Required: true},
"namespace": schema.StringAttribute{Required: true},
"agent_policy_id": schema.StringAttribute{Required: true},
"description": schema.StringAttribute{Optional: true},
"enabled": schema.BoolAttribute{Computed: true, Optional: true, Default: booldefault.StaticBool(true)},
"force": schema.BoolAttribute{Optional: true},
"integration_name": schema.StringAttribute{Required: true},
"integration_version": schema.StringAttribute{Required: true},
"vars_json": schema.StringAttribute{Computed: true, Optional: true, Sensitive: true},
},
Blocks: map[string]schema.Block{
"input": schema.ListNestedBlock{
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"input_id": schema.StringAttribute{Required: true},
"enabled": schema.BoolAttribute{Computed: true, Optional: true, Default: booldefault.StaticBool(true)},
"streams_json": schema.StringAttribute{Computed: true, Optional: true, Sensitive: true},
"vars_json": schema.StringAttribute{Computed: true, Optional: true, Sensitive: true},
},
},
},
},
}
}

func getInputTypeV0() attr.Type {
return getSchemaV0().Blocks["input"].Type().(attr.TypeWithElementType).ElementType()
}

type integrationPolicyModelV0 struct {
ID types.String `tfsdk:"id"`
PolicyID types.String `tfsdk:"policy_id"`
Name types.String `tfsdk:"name"`
Namespace types.String `tfsdk:"namespace"`
AgentPolicyID types.String `tfsdk:"agent_policy_id"`
Description types.String `tfsdk:"description"`
Enabled types.Bool `tfsdk:"enabled"`
Force types.Bool `tfsdk:"force"`
IntegrationName types.String `tfsdk:"integration_name"`
IntegrationVersion types.String `tfsdk:"integration_version"`
Input types.List `tfsdk:"input"` //> integrationPolicyInputModelV0
VarsJson types.String `tfsdk:"vars_json"`
}

type integrationPolicyInputModelV0 struct {
InputID types.String `tfsdk:"input_id"`
Enabled types.Bool `tfsdk:"enabled"`
StreamsJson types.String `tfsdk:"streams_json"`
VarsJson types.String `tfsdk:"vars_json"`
}

// The schema between V0 and V1 is mostly the same, however vars_json and
// streams_json saved "" values to the state when null values were in the
// config. jsontypes.Normalized correctly states this is invalid JSON.
func upgradeV0(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) {
var stateModel integrationPolicyModelV0

diags := req.State.Get(ctx, &stateModel)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

if varsJSON := stateModel.VarsJson.ValueStringPointer(); varsJSON != nil {
if *varsJSON == "" {
stateModel.VarsJson = types.StringNull()
}
}

inputs := utils.ListTypeAs[integrationPolicyInputModelV0](ctx, stateModel.Input, path.Root("input"), &resp.Diagnostics)
for index, input := range inputs {
if varsJSON := input.VarsJson.ValueStringPointer(); varsJSON != nil {
if *varsJSON == "" {
input.VarsJson = types.StringNull()
}
}
if streamsJSON := input.StreamsJson.ValueStringPointer(); streamsJSON != nil {
if *streamsJSON == "" {
input.StreamsJson = types.StringNull()
}
}
inputs[index] = input
}

stateModel.Input = utils.ListValueFrom(ctx, inputs, getInputTypeV0(), path.Root("input"), &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}

diags = resp.State.Set(ctx, stateModel)
resp.Diagnostics.Append(diags...)
}
Loading
Loading