Skip to content

Commit 6c2f52b

Browse files
Sort Fleet integration policy inputs to ensure consistency (#494)
* Sort Fleet integration policy inputs to ensure consistency - When new inputs are read from the Fleet API, the list is sorted according to the existing plan. Any new inputs added from the API will be moved to the end of the list. This ensures a consistency of inputs and prevents unnecssary changes from appearing. * Changelog * Extract sort function and add unit test
1 parent 86cb705 commit 6c2f52b

File tree

3 files changed

+106
-6
lines changed

3 files changed

+106
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- Rename fleet package objects to `elasticstack_fleet_integration` and `elasticstack_fleet_integration_policy` ([#476](https://github.com/elastic/terraform-provider-elasticstack/pull/476))
99
- Fix a provider crash when managing SLOs outside of the default Kibana space. ([#485](https://github.com/elastic/terraform-provider-elasticstack/pull/485))
1010
- Make input optional for `elasticstack_fleet_integration_policy` ([#493](https://github.com/elastic/terraform-provider-elasticstack/pull/493))
11+
- Sort Fleet integration policy inputs to ensure consistency ([#494](https://github.com/elastic/terraform-provider-elasticstack/pull/494))
1112

1213
## [0.10.0] - 2023-11-02
1314

internal/fleet/integration_policy_resource.go

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package fleet
33
import (
44
"context"
55
"encoding/json"
6+
"sort"
67

78
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
89
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -340,9 +341,9 @@ func resourceIntegrationPolicyRead(ctx context.Context, d *schema.ResourceData,
340341
}
341342
}
342343

343-
var inputs []any
344+
newInputs := make([]any, 0, len(pkgPolicy.Inputs))
344345
for inputID, input := range pkgPolicy.Inputs {
345-
inputMap := map[string]any{
346+
inputData := map[string]any{
346347
"input_id": inputID,
347348
"enabled": input.Enabled,
348349
}
@@ -352,19 +353,23 @@ func resourceIntegrationPolicyRead(ctx context.Context, d *schema.ResourceData,
352353
if err != nil {
353354
return diag.FromErr(err)
354355
}
355-
inputMap["streams_json"] = string(data)
356+
inputData["streams_json"] = string(data)
356357
}
357358
if input.Vars != nil {
358359
data, err := json.Marshal(*input.Vars)
359360
if err != nil {
360361
return diag.FromErr(err)
361362
}
362-
inputMap["vars_json"] = string(data)
363+
inputData["vars_json"] = string(data)
363364
}
364365

365-
inputs = append(inputs, inputMap)
366+
newInputs = append(newInputs, inputData)
366367
}
367-
if err := d.Set("input", inputs); err != nil {
368+
369+
existingInputs, _ := d.Get("input").([]any)
370+
sortInputs(newInputs, existingInputs)
371+
372+
if err := d.Set("input", newInputs); err != nil {
368373
return diag.FromErr(err)
369374
}
370375

@@ -386,3 +391,34 @@ func resourceIntegrationPolicyDelete(ctx context.Context, d *schema.ResourceData
386391

387392
return diags
388393
}
394+
395+
// sortInputs will sort the 'incoming' list of input definitions based on
396+
// the order of inputs defined in the 'existing' list. Inputs not present in
397+
// 'existing' will be placed at the end of the list. Inputs are identified by
398+
// their ID ('input_id'). The 'incoming' slice will be sorted in-place.
399+
func sortInputs(incoming []any, existing []any) {
400+
idToIndex := make(map[string]int, len(existing))
401+
for i, v := range existing {
402+
inputData, _ := v.(map[string]any)
403+
inputID, _ := inputData["input_id"].(string)
404+
idToIndex[inputID] = i
405+
}
406+
407+
sort.Slice(incoming, func(i, j int) bool {
408+
iInput, _ := incoming[i].(map[string]any)
409+
iID, _ := iInput["input_id"].(string)
410+
iIdx, ok := idToIndex[iID]
411+
if !ok {
412+
return false
413+
}
414+
415+
jInput, _ := incoming[j].(map[string]any)
416+
jID, _ := jInput["input_id"].(string)
417+
jIdx, ok := idToIndex[jID]
418+
if !ok {
419+
return true
420+
}
421+
422+
return iIdx < jIdx
423+
})
424+
}

internal/fleet/shared_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package fleet
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func Test_SortInputs(t *testing.T) {
10+
t.Run("WithExisting", func(t *testing.T) {
11+
existing := []any{
12+
map[string]any{"input_id": "A", "enabled": true},
13+
map[string]any{"input_id": "B", "enabled": true},
14+
map[string]any{"input_id": "C", "enabled": true},
15+
map[string]any{"input_id": "D", "enabled": true},
16+
map[string]any{"input_id": "E", "enabled": true},
17+
}
18+
19+
incoming := []any{
20+
map[string]any{"input_id": "G", "enabled": true},
21+
map[string]any{"input_id": "F", "enabled": true},
22+
map[string]any{"input_id": "B", "enabled": true},
23+
map[string]any{"input_id": "E", "enabled": true},
24+
map[string]any{"input_id": "C", "enabled": true},
25+
}
26+
27+
want := []any{
28+
map[string]any{"input_id": "B", "enabled": true},
29+
map[string]any{"input_id": "C", "enabled": true},
30+
map[string]any{"input_id": "E", "enabled": true},
31+
map[string]any{"input_id": "G", "enabled": true},
32+
map[string]any{"input_id": "F", "enabled": true},
33+
}
34+
35+
sortInputs(incoming, existing)
36+
37+
require.Equal(t, want, incoming)
38+
})
39+
40+
t.Run("WithEmpty", func(t *testing.T) {
41+
var existing []any
42+
43+
incoming := []any{
44+
map[string]any{"input_id": "G", "enabled": true},
45+
map[string]any{"input_id": "F", "enabled": true},
46+
map[string]any{"input_id": "B", "enabled": true},
47+
map[string]any{"input_id": "E", "enabled": true},
48+
map[string]any{"input_id": "C", "enabled": true},
49+
}
50+
51+
want := []any{
52+
map[string]any{"input_id": "G", "enabled": true},
53+
map[string]any{"input_id": "F", "enabled": true},
54+
map[string]any{"input_id": "B", "enabled": true},
55+
map[string]any{"input_id": "E", "enabled": true},
56+
map[string]any{"input_id": "C", "enabled": true},
57+
}
58+
59+
sortInputs(incoming, existing)
60+
61+
require.Equal(t, want, incoming)
62+
})
63+
}

0 commit comments

Comments
 (0)