@@ -3,7 +3,6 @@ package integration_policy
33import (
44 "context"
55 "fmt"
6- "sort"
76
87 "github.com/elastic/terraform-provider-elasticstack/generated/kbapi"
98 "github.com/elastic/terraform-provider-elasticstack/internal/utils"
@@ -31,16 +30,20 @@ type integrationPolicyModel struct {
3130 IntegrationName types.String `tfsdk:"integration_name"`
3231 IntegrationVersion types.String `tfsdk:"integration_version"`
3332 OutputID types.String `tfsdk:"output_id"`
34- Input types.List `tfsdk:"input "` //> integrationPolicyInputModel
33+ Inputs types.Map `tfsdk:"inputs "` //> integrationPolicyInputsModel
3534 VarsJson jsontypes.Normalized `tfsdk:"vars_json"`
3635 SpaceIds types.Set `tfsdk:"space_ids"`
3736}
3837
39- type integrationPolicyInputModel struct {
40- InputID types.String `tfsdk:"input_id"`
41- Enabled types.Bool `tfsdk:"enabled"`
42- StreamsJson jsontypes.Normalized `tfsdk:"streams_json"`
43- VarsJson jsontypes.Normalized `tfsdk:"vars_json"`
38+ type integrationPolicyInputsModel struct {
39+ Enabled types.Bool `tfsdk:"enabled"`
40+ Vars jsontypes.Normalized `tfsdk:"vars"`
41+ Streams types.Map `tfsdk:"streams"` //> integrationPolicyInputStreamModel
42+ }
43+
44+ type integrationPolicyInputStreamModel struct {
45+ Enabled types.Bool `tfsdk:"enabled"`
46+ Vars jsontypes.Normalized `tfsdk:"vars"`
4447}
4548
4649func (model * integrationPolicyModel ) populateFromAPI (ctx context.Context , data * kbapi.PackagePolicy ) diag.Diagnostics {
@@ -107,20 +110,19 @@ func (model *integrationPolicyModel) populateFromAPI(ctx context.Context, data *
107110 model .SpaceIds = types .SetNull (types .StringType )
108111 }
109112 // If originally set but API didn't return it, keep the original value
110-
111- model .populateInputFromAPI (ctx , data .Inputs , & diags )
113+ model .populateInputsFromAPI (ctx , data .Inputs , & diags )
112114
113115 return diags
114116}
115117
116- func (model * integrationPolicyModel ) populateInputFromAPI (ctx context.Context , inputs map [string ]kbapi.PackagePolicyInput , diags * diag.Diagnostics ) {
118+ func (model * integrationPolicyModel ) populateInputsFromAPI (ctx context.Context , inputs map [string ]kbapi.PackagePolicyInput , diags * diag.Diagnostics ) {
117119 // Handle input population based on context:
118120 // 1. If model.Input is unknown: we're importing or reading fresh state → populate from API
119121 // 2. If model.Input is known and null/empty: user explicitly didn't configure inputs → don't populate (avoid inconsistent state)
120122 // 3. If model.Input is known and has values: user configured inputs → populate from API
121123
122- isInputKnown := utils .IsKnown (model .Input )
123- isInputNullOrEmpty := model .Input .IsNull () || (isInputKnown && len (model .Input .Elements ()) == 0 )
124+ isInputKnown := utils .IsKnown (model .Inputs )
125+ isInputNullOrEmpty := model .Inputs .IsNull () || (isInputKnown && len (model .Inputs .Elements ()) == 0 )
124126
125127 // Case 1: Unknown (import/fresh read) - always populate
126128 if ! isInputKnown {
@@ -129,32 +131,43 @@ func (model *integrationPolicyModel) populateInputFromAPI(ctx context.Context, i
129131 } else if isInputNullOrEmpty {
130132 // Case 2: Known and null/empty - user explicitly didn't configure inputs
131133 // Don't populate to avoid "Provider produced inconsistent result" error
132- model .Input = types .ListNull ( getInputTypeV1 ())
134+ model .Inputs = types .MapNull ( getInputsTypes ())
133135 return
134136 }
135137 // Case 3: Known and not null/empty - user configured inputs, populate from API (continue below)
136138
137- newInputs := utils .TransformMapToSlice (ctx , inputs , path .Root ("input" ), diags ,
138- func (inputData kbapi.PackagePolicyInput , meta utils.MapMeta ) integrationPolicyInputModel {
139- return integrationPolicyInputModel {
140- InputID : types .StringValue (meta .Key ),
141- Enabled : types .BoolPointerValue (inputData .Enabled ),
142- StreamsJson : utils .MapToNormalizedType (utils .Deref (inputData .Streams ), meta .Path .AtName ("streams_json" ), diags ),
143- VarsJson : utils .MapToNormalizedType (utils .Deref (inputData .Vars ), meta .Path .AtName ("vars_json" ), diags ),
144- }
145- })
146- if newInputs == nil {
147- model .Input = types .ListNull (getInputTypeV1 ())
148- } else {
149- oldInputs := utils .ListTypeAs [integrationPolicyInputModel ](ctx , model .Input , path .Root ("input" ), diags )
139+ newInputs := make (map [string ]integrationPolicyInputsModel )
140+ for inputID , inputData := range inputs {
141+ inputModel := integrationPolicyInputsModel {
142+ Enabled : types .BoolPointerValue (inputData .Enabled ),
143+ Vars : utils .MapToNormalizedType (utils .Deref (inputData .Vars ), path .Root ("inputs" ).AtMapKey (inputID ).AtName ("vars" ), diags ),
144+ }
150145
151- sortInputs (newInputs , oldInputs )
146+ // Populate streams
147+ if inputData .Streams != nil && len (* inputData .Streams ) > 0 {
148+ streams := make (map [string ]integrationPolicyInputStreamModel )
149+ for streamID , streamData := range * inputData .Streams {
150+ streamModel := integrationPolicyInputStreamModel {
151+ Enabled : types .BoolPointerValue (streamData .Enabled ),
152+ Vars : utils .MapToNormalizedType (utils .Deref (streamData .Vars ), path .Root ("inputs" ).AtMapKey (inputID ).AtName ("streams" ).AtMapKey (streamID ).AtName ("vars" ), diags ),
153+ }
152154
153- inputList , d := types .ListValueFrom (ctx , getInputTypeV1 (), newInputs )
154- diags .Append (d ... )
155+ streams [streamID ] = streamModel
156+ }
157+
158+ streamsMap , d := types .MapValueFrom (ctx , getInputStreamType (), streams )
159+ diags .Append (d ... )
160+ inputModel .Streams = streamsMap
161+ } else {
162+ inputModel .Streams = types .MapNull (getInputStreamType ())
163+ }
155164
156- model . Input = inputList
165+ newInputs [ inputID ] = inputModel
157166 }
167+
168+ inputsMap , d := types .MapValueFrom (ctx , getInputsTypes (), newInputs )
169+ diags .Append (d ... )
170+ model .Inputs = inputsMap
158171}
159172
160173func (model integrationPolicyModel ) toAPIModel (ctx context.Context , isUpdate bool , feat features ) (kbapi.PackagePolicyRequest , diag.Diagnostics ) {
@@ -218,51 +231,53 @@ func (model integrationPolicyModel) toAPIModel(ctx context.Context, isUpdate boo
218231 body .Id = model .ID .ValueStringPointer ()
219232 }
220233
221- body .Inputs = utils .MapRef (utils .ListTypeToMap (ctx , model .Input , path .Root ("input" ), & diags ,
222- func (inputModel integrationPolicyInputModel , meta utils.ListMeta ) (string , kbapi.PackagePolicyRequestInput ) {
223- return inputModel .InputID .ValueString (), kbapi.PackagePolicyRequestInput {
224- Enabled : inputModel .Enabled .ValueBoolPointer (),
225- Streams : utils .MapRef (utils .NormalizedTypeToMap [kbapi.PackagePolicyRequestInputStream ](inputModel .StreamsJson , meta .Path .AtName ("streams_json" ), & diags )),
226- Vars : utils .MapRef (utils .NormalizedTypeToMap [any ](inputModel .VarsJson , meta .Path .AtName ("vars_json" ), & diags )),
227- }
228- }))
234+ if utils .IsKnown (model .Inputs ) && len (model .Inputs .Elements ()) > 0 {
235+ // Use the 'inputs' attribute (v2 format)
236+ body .Inputs = utils .MapRef (model .toAPIInputsFromInputsAttribute (ctx , & diags ))
237+ }
229238
230239 // Note: space_ids is read-only for integration policies and inherited from the agent policy
231240
232241 return body , diags
233242}
234243
235- // sortInputs will sort the 'incoming' list of input definitions based on
236- // the order of inputs defined in the 'existing' list. Inputs not present in
237- // 'existing' will be placed at the end of the list. Inputs are identified by
238- // their ID ('input_id'). The 'incoming' slice will be sorted in-place.
239- func sortInputs (incoming []integrationPolicyInputModel , existing []integrationPolicyInputModel ) {
240- if len (existing ) == 0 {
241- sort .Slice (incoming , func (i , j int ) bool {
242- return incoming [i ].InputID .ValueString () < incoming [j ].InputID .ValueString ()
243- })
244- return
244+ // toAPIInputsFromInputsAttribute converts the 'inputs' attribute to the API model format
245+ func (model integrationPolicyModel ) toAPIInputsFromInputsAttribute (ctx context.Context , diags * diag.Diagnostics ) map [string ]kbapi.PackagePolicyRequestInput {
246+ if ! utils .IsKnown (model .Inputs ) {
247+ return nil
245248 }
246249
247- idToIndex := make (map [string ]int , len (existing ))
248- for index , inputData := range existing {
249- inputID := inputData .InputID .ValueString ()
250- idToIndex [inputID ] = index
250+ inputsMap := utils .MapTypeAs [integrationPolicyInputsModel ](ctx , model .Inputs , path .Root ("inputs" ), diags )
251+ if inputsMap == nil {
252+ return nil
251253 }
252254
253- sort .Slice (incoming , func (i , j int ) bool {
254- iID := incoming [i ].InputID .ValueString ()
255- iIdx , ok := idToIndex [iID ]
256- if ! ok {
257- return false
255+ result := make (map [string ]kbapi.PackagePolicyRequestInput , len (inputsMap ))
256+ for inputID , inputModel := range inputsMap {
257+ inputPath := path .Root ("inputs" ).AtMapKey (inputID )
258+
259+ apiInput := kbapi.PackagePolicyRequestInput {
260+ Enabled : inputModel .Enabled .ValueBoolPointer (),
261+ Vars : utils .MapRef (utils .NormalizedTypeToMap [any ](inputModel .Vars , inputPath .AtName ("vars" ), diags )),
258262 }
259263
260- jID := incoming [j ].InputID .ValueString ()
261- jIdx , ok := idToIndex [jID ]
262- if ! ok {
263- return true
264+ // Convert streams if present
265+ if utils .IsKnown (inputModel .Streams ) && len (inputModel .Streams .Elements ()) > 0 {
266+ streamsMap := utils .MapTypeAs [integrationPolicyInputStreamModel ](ctx , inputModel .Streams , inputPath .AtName ("streams" ), diags )
267+ if streamsMap != nil {
268+ streams := make (map [string ]kbapi.PackagePolicyRequestInputStream , len (streamsMap ))
269+ for streamID , streamModel := range streamsMap {
270+ streams [streamID ] = kbapi.PackagePolicyRequestInputStream {
271+ Enabled : streamModel .Enabled .ValueBoolPointer (),
272+ Vars : utils .MapRef (utils .NormalizedTypeToMap [any ](streamModel .Vars , inputPath .AtName ("streams" ).AtMapKey (streamID ).AtName ("vars" ), diags )),
273+ }
274+ }
275+ apiInput .Streams = & streams
276+ }
264277 }
265278
266- return iIdx < jIdx
267- })
279+ result [inputID ] = apiInput
280+ }
281+
282+ return result
268283}
0 commit comments