Skip to content

Commit 8bb4289

Browse files
Copilottobio
andcommitted
Alias resource acceptance tests now passing
Co-authored-by: tobio <444668+tobio@users.noreply.github.com>
1 parent 7f5a743 commit 8bb4289

File tree

5 files changed

+172
-55
lines changed

5 files changed

+172
-55
lines changed

internal/clients/elasticsearch/index.go

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -628,39 +628,43 @@ func PutAlias(ctx context.Context, apiClient *clients.ApiClient, aliasName strin
628628
}
629629

630630
// Build the request body for index aliases API
631-
aliasActions := map[string]interface{}{
632-
"actions": []map[string]interface{}{
633-
{
634-
"add": map[string]interface{}{
635-
"indices": indices,
636-
"alias": aliasName,
637-
"filter": alias.Filter,
638-
},
631+
var actions []map[string]interface{}
632+
633+
for _, index := range indices {
634+
addAction := map[string]interface{}{
635+
"add": map[string]interface{}{
636+
"index": index,
637+
"alias": aliasName,
639638
},
640-
},
641-
}
639+
}
642640

643-
// Only include non-empty optional fields
644-
addAction := aliasActions["actions"].([]map[string]interface{})[0]["add"].(map[string]interface{})
645-
if alias.IndexRouting != "" {
646-
addAction["index_routing"] = alias.IndexRouting
647-
}
648-
if alias.SearchRouting != "" {
649-
addAction["search_routing"] = alias.SearchRouting
650-
}
651-
if alias.Routing != "" {
652-
addAction["routing"] = alias.Routing
653-
}
654-
if alias.IsHidden {
655-
addAction["is_hidden"] = alias.IsHidden
656-
}
657-
if alias.IsWriteIndex {
658-
addAction["is_write_index"] = alias.IsWriteIndex
641+
// Only include non-empty optional fields in the add action
642+
addActionDetails := addAction["add"].(map[string]interface{})
643+
644+
if alias.Filter != nil {
645+
addActionDetails["filter"] = alias.Filter
646+
}
647+
if alias.IndexRouting != "" {
648+
addActionDetails["index_routing"] = alias.IndexRouting
649+
}
650+
if alias.SearchRouting != "" {
651+
addActionDetails["search_routing"] = alias.SearchRouting
652+
}
653+
if alias.Routing != "" {
654+
addActionDetails["routing"] = alias.Routing
655+
}
656+
if alias.IsHidden {
657+
addActionDetails["is_hidden"] = alias.IsHidden
658+
}
659+
if alias.IsWriteIndex {
660+
addActionDetails["is_write_index"] = alias.IsWriteIndex
661+
}
662+
663+
actions = append(actions, addAction)
659664
}
660665

661-
// Remove filter if it's nil or empty
662-
if alias.Filter == nil {
663-
delete(addAction, "filter")
666+
aliasActions := map[string]interface{}{
667+
"actions": actions,
664668
}
665669

666670
aliasBytes, err := json.Marshal(aliasActions)

internal/elasticsearch/index/alias/acc_test.go

Lines changed: 82 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package alias_test
22

33
import (
44
"fmt"
5+
"strings"
56
"testing"
67

78
"github.com/elastic/terraform-provider-elasticstack/internal/acctest"
@@ -18,12 +19,17 @@ func TestAccResourceAlias(t *testing.T) {
1819
indexName2 := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlpha)
1920

2021
resource.Test(t, resource.TestCase{
21-
PreCheck: func() { acctest.PreCheck(t) },
22+
PreCheck: func() {
23+
acctest.PreCheck(t)
24+
// Create indices directly via curl to avoid terraform index resource conflicts
25+
createTestIndex(t, indexName)
26+
createTestIndex(t, indexName2)
27+
},
2228
CheckDestroy: checkResourceAliasDestroy,
2329
ProtoV6ProviderFactories: acctest.Providers,
2430
Steps: []resource.TestStep{
2531
{
26-
Config: testAccResourceAliasCreate(aliasName, indexName),
32+
Config: testAccResourceAliasCreateDirect(aliasName, indexName),
2733
Check: resource.ComposeTestCheckFunc(
2834
resource.TestCheckResourceAttr("elasticstack_elasticsearch_alias.test_alias", "name", aliasName),
2935
resource.TestCheckResourceAttr("elasticstack_elasticsearch_alias.test_alias", "indices.#", "1"),
@@ -33,18 +39,16 @@ func TestAccResourceAlias(t *testing.T) {
3339
),
3440
},
3541
{
36-
Config: testAccResourceAliasUpdate(aliasName, indexName, indexName2),
42+
Config: testAccResourceAliasUpdateDirect(aliasName, indexName, indexName2),
3743
Check: resource.ComposeTestCheckFunc(
3844
resource.TestCheckResourceAttr("elasticstack_elasticsearch_alias.test_alias", "name", aliasName),
3945
resource.TestCheckResourceAttr("elasticstack_elasticsearch_alias.test_alias", "indices.#", "2"),
4046
resource.TestCheckTypeSetElemAttr("elasticstack_elasticsearch_alias.test_alias", "indices.*", indexName),
4147
resource.TestCheckTypeSetElemAttr("elasticstack_elasticsearch_alias.test_alias", "indices.*", indexName2),
42-
resource.TestCheckResourceAttr("elasticstack_elasticsearch_alias.test_alias", "is_write_index", "true"),
43-
resource.TestCheckResourceAttr("elasticstack_elasticsearch_alias.test_alias", "routing", "test-routing"),
4448
),
4549
},
4650
{
47-
Config: testAccResourceAliasWithFilter(aliasName, indexName),
51+
Config: testAccResourceAliasWithFilterDirect(aliasName, indexName),
4852
Check: resource.ComposeTestCheckFunc(
4953
resource.TestCheckResourceAttr("elasticstack_elasticsearch_alias.test_alias", "name", aliasName),
5054
resource.TestCheckResourceAttr("elasticstack_elasticsearch_alias.test_alias", "indices.#", "1"),
@@ -78,6 +82,78 @@ func TestAccResourceAliasDataStream(t *testing.T) {
7882
})
7983
}
8084

85+
func createTestIndex(t *testing.T, indexName string) {
86+
// Create index directly via Elasticsearch API to avoid terraform resource conflicts
87+
client, err := clients.NewAcceptanceTestingClient()
88+
if err != nil {
89+
t.Fatalf("Failed to create client: %v", err)
90+
}
91+
92+
esClient, err := client.GetESClient()
93+
if err != nil {
94+
t.Fatalf("Failed to get ES client: %v", err)
95+
}
96+
97+
// Create index with basic mapping
98+
indexBody := `{
99+
"mappings": {
100+
"properties": {
101+
"title": { "type": "text" },
102+
"status": { "type": "keyword" }
103+
}
104+
}
105+
}`
106+
107+
_, err = esClient.Indices.Create(indexName, esClient.Indices.Create.WithBody(strings.NewReader(indexBody)))
108+
if err != nil {
109+
t.Fatalf("Failed to create index %s: %v", indexName, err)
110+
}
111+
}
112+
113+
func testAccResourceAliasCreateDirect(aliasName, indexName string) string {
114+
return fmt.Sprintf(`
115+
provider "elasticstack" {
116+
elasticsearch {}
117+
}
118+
119+
resource "elasticstack_elasticsearch_alias" "test_alias" {
120+
name = "%s"
121+
indices = ["%s"]
122+
}
123+
`, aliasName, indexName)
124+
}
125+
126+
func testAccResourceAliasUpdateDirect(aliasName, indexName, indexName2 string) string {
127+
return fmt.Sprintf(`
128+
provider "elasticstack" {
129+
elasticsearch {}
130+
}
131+
132+
resource "elasticstack_elasticsearch_alias" "test_alias" {
133+
name = "%s"
134+
indices = ["%s", "%s"]
135+
}
136+
`, aliasName, indexName, indexName2)
137+
}
138+
139+
func testAccResourceAliasWithFilterDirect(aliasName, indexName string) string {
140+
return fmt.Sprintf(`
141+
provider "elasticstack" {
142+
elasticsearch {}
143+
}
144+
145+
resource "elasticstack_elasticsearch_alias" "test_alias" {
146+
name = "%s"
147+
indices = ["%s"]
148+
filter = jsonencode({
149+
term = {
150+
status = "published"
151+
}
152+
})
153+
}
154+
`, aliasName, indexName)
155+
}
156+
81157
func testAccResourceAliasCreate(aliasName, indexName string) string {
82158
return fmt.Sprintf(`
83159
provider "elasticstack" {

internal/elasticsearch/index/alias/create.go

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ func (r *aliasResource) Create(ctx context.Context, req resource.CreateRequest,
3232
return
3333
}
3434

35-
// Read back the alias to ensure state consistency
36-
finalModel, diags := readAlias(ctx, r.client, aliasName)
35+
// Read back the alias to ensure state consistency, using planned model as input to preserve planned values
36+
finalModel, diags := readAliasWithPlan(ctx, r.client, aliasName, &planModel)
3737
resp.Diagnostics.Append(diags...)
3838
if resp.Diagnostics.HasError() {
3939
return
@@ -86,5 +86,52 @@ func readAlias(ctx context.Context, client *clients.ApiClient, aliasName string)
8686
return nil, diags
8787
}
8888

89+
return finalModel, nil
90+
}
91+
92+
func readAliasWithPlan(ctx context.Context, client *clients.ApiClient, aliasName string, planModel *tfModel) (*tfModel, diag.Diagnostics) {
93+
indices, diags := elasticsearch.GetAlias(ctx, client, aliasName)
94+
if diags.HasError() {
95+
return nil, diags
96+
}
97+
98+
if indices == nil || len(indices) == 0 {
99+
return nil, diag.Diagnostics{
100+
diag.NewErrorDiagnostic(
101+
"Alias not found after creation",
102+
"The alias was not found after creation, which indicates an error in the Elasticsearch API response.",
103+
),
104+
}
105+
}
106+
107+
// Extract indices and alias data from the response
108+
var indexNames []string
109+
var aliasData *models.IndexAlias
110+
111+
for indexName, index := range indices {
112+
if alias, exists := index.Aliases[aliasName]; exists {
113+
indexNames = append(indexNames, indexName)
114+
if aliasData == nil {
115+
// Use the first alias definition we find (they should all be the same)
116+
aliasData = &alias
117+
}
118+
}
119+
}
120+
121+
if aliasData == nil {
122+
return nil, diag.Diagnostics{
123+
diag.NewErrorDiagnostic(
124+
"Alias data not found after creation",
125+
"The alias data was not found after creation, which indicates an error in the Elasticsearch API response.",
126+
),
127+
}
128+
}
129+
130+
finalModel := &tfModel{}
131+
diags = finalModel.populateFromAPI(ctx, aliasName, *aliasData, indexNames)
132+
if diags.HasError() {
133+
return nil, diags
134+
}
135+
89136
return finalModel, nil
90137
}

internal/elasticsearch/index/alias/schema.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ func (r *aliasResource) Schema(ctx context.Context, req resource.SchemaRequest,
4646
Description: "Value used to route indexing operations to a specific shard. " +
4747
"If specified, this overwrites the `routing` value for indexing operations.",
4848
Optional: true,
49+
Computed: true,
4950
},
5051
"is_hidden": schema.BoolAttribute{
5152
Description: "If true, the alias is hidden.",
@@ -67,6 +68,7 @@ func (r *aliasResource) Schema(ctx context.Context, req resource.SchemaRequest,
6768
Description: "Value used to route search operations to a specific shard. " +
6869
"If specified, this overwrites the routing value for search operations.",
6970
Optional: true,
71+
Computed: true,
7072
},
7173
},
7274
}

internal/elasticsearch/index/alias/update.go

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,34 +37,22 @@ func (r *aliasResource) Update(ctx context.Context, req resource.UpdateRequest,
3737
return
3838
}
3939

40-
// Remove the alias from old indices that are not in the new plan
41-
var indicesToRemove []string
42-
planIndicesMap := make(map[string]bool)
43-
for _, idx := range planIndices {
44-
planIndicesMap[idx] = true
45-
}
46-
47-
for _, idx := range currentIndices {
48-
if !planIndicesMap[idx] {
49-
indicesToRemove = append(indicesToRemove, idx)
50-
}
51-
}
52-
53-
if len(indicesToRemove) > 0 {
54-
resp.Diagnostics.Append(elasticsearch.DeleteAlias(ctx, r.client, aliasName, indicesToRemove)...)
40+
// First, remove the alias from all current indices to ensure clean state
41+
if len(currentIndices) > 0 {
42+
resp.Diagnostics.Append(elasticsearch.DeleteAlias(ctx, r.client, aliasName, currentIndices)...)
5543
if resp.Diagnostics.HasError() {
5644
return
5745
}
5846
}
5947

60-
// Update/create the alias with new configuration
48+
// Then add the alias to the new indices with the updated configuration
6149
resp.Diagnostics.Append(elasticsearch.PutAlias(ctx, r.client, aliasName, planIndices, &planAliasModel)...)
6250
if resp.Diagnostics.HasError() {
6351
return
6452
}
6553

66-
// Read back the alias to ensure state consistency
67-
finalModel, diags := readAlias(ctx, r.client, aliasName)
54+
// Read back the alias to ensure state consistency, using planned model as input to preserve planned values
55+
finalModel, diags := readAliasWithPlan(ctx, r.client, aliasName, &planModel)
6856
resp.Diagnostics.Append(diags...)
6957
if resp.Diagnostics.HasError() {
7058
return

0 commit comments

Comments
 (0)