Skip to content

Commit

Permalink
Support index alias update (#212)
Browse files Browse the repository at this point in the history
Signed-off-by: Prudhvi Godithi <[email protected]>
  • Loading branch information
prudhvigodithi authored Sep 18, 2024
1 parent d86d6a3 commit 790834e
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 1 deletion.
21 changes: 21 additions & 0 deletions docs/resources/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,27 @@ resource "opensearch_index" "test-simple-index" {
}
EOF
}
## Index with aliases
resource "opensearch_index" "index" {
name = "sample"
aliases = jsonencode(
{
"log": {
"is_write_index": true
}
}
)
number_of_replicas = "1"
number_of_shards = "1"
mappings = jsonencode({
"properties": {
"age": {
"type": "integer"
}
}
})
}
```

<!-- schema generated by tfplugindocs -->
Expand Down
File renamed without changes.
21 changes: 21 additions & 0 deletions examples/resources/opensearch_index/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,24 @@ resource "opensearch_index" "test-simple-index" {
}
EOF
}

## Index with aliases
resource "opensearch_index" "index" {
name = "sample"
aliases = jsonencode(
{
"log": {
"is_write_index": true
}
}
)
number_of_replicas = "1"
number_of_shards = "1"
mappings = jsonencode({
"properties": {
"age": {
"type": "integer"
}
}
})
}
58 changes: 57 additions & 1 deletion provider/resource_opensearch_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,6 @@ var (
Optional: true,
// In order to not handle the separate endpoint of alias updates, updates
// are not allowed via this provider currently.
ForceNew: true,
ValidateFunc: validation.StringIsJSON,
},
"analysis_analyzer": {
Expand Down Expand Up @@ -666,6 +665,21 @@ func resourceOpensearchIndexUpdate(d *schema.ResourceData, meta interface{}) err
}
}

// Check for alias changes
if d.HasChange("aliases") {
oldAliases, newAliases := d.GetChange("aliases")

// Convert the alias JSON strings to maps
var oldAliasesMap, newAliasesMap map[string]interface{}
_ = json.Unmarshal([]byte(oldAliases.(string)), &oldAliasesMap)
_ = json.Unmarshal([]byte(newAliases.(string)), &newAliasesMap)

// Update the aliases using OpenSearch API
if err := updateAliases(d.Id(), oldAliasesMap, newAliasesMap, meta); err != nil {
return fmt.Errorf("error updating aliases: %v", err)
}
}

// if we're not changing any settings, no-op this function
if len(settings) == 0 {
return resourceOpensearchIndexRead(d, meta)
Expand Down Expand Up @@ -831,3 +845,45 @@ func resourceOpensearchIndexRead(d *schema.ResourceData, meta interface{}) error

return nil
}

func updateAliases(index string, oldAliases, newAliases map[string]interface{}, meta interface{}) error {
ctx := context.Background()

osClient, err := getClient(meta.(*ProviderConf))
if err != nil {
return err
}

// Remove old aliases that are not present in the new aliases
for aliasName := range oldAliases {
if _, exists := newAliases[aliasName]; !exists {
aliasDeletePath := fmt.Sprintf("/%s/_alias/%s", index, aliasName)

_, err := osClient.PerformRequest(ctx, elastic7.PerformRequestOptions{
Method: "DELETE",
Path: aliasDeletePath,
})

if err != nil {
return fmt.Errorf("error removing alias %s: %v", aliasName, err)
}
}
}

// Add or update new aliases
for aliasName, aliasConfig := range newAliases {
aliasUpdatePath := fmt.Sprintf("/%s/_alias/%s", index, aliasName)

_, err := osClient.PerformRequest(ctx, elastic7.PerformRequestOptions{
Method: "PUT",
Path: aliasUpdatePath,
Body: aliasConfig,
})

if err != nil {
return fmt.Errorf("error adding/updating alias %s: %v", aliasName, err)
}
}

return nil
}
149 changes: 149 additions & 0 deletions provider/resource_opensearch_index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -639,3 +639,152 @@ func checkOpensearchIndexDestroy(s *terraform.State) error {

return nil
}

const testAccOpensearchIndexWithAlias = `
resource "opensearch_index" "test" {
name = "terraform-test-with-alias"
number_of_shards = 1
number_of_replicas = 1
aliases = jsonencode({
"alias1" = {
"is_write_index" = false
}
})
}
`

func TestAccOpensearchIndexWithAlias(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: checkOpensearchIndexDestroy,
Steps: []resource.TestStep{
{
Config: testAccOpensearchIndexWithAlias,
Check: resource.ComposeTestCheckFunc(
checkOpensearchIndexExists("opensearch_index.test"),
checkOpensearchAliasExists("terraform-test-with-alias", "alias1"),
),
},
},
})
}

func checkOpensearchAliasExists(indexName, aliasName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
osClient, err := getClient(testAccProvider.Meta().(*ProviderConf))
if err != nil {
return err
}

// Check if the alias exists for the index
aliases, err := osClient.CatAliases().Alias(aliasName).Do(context.TODO())
if err != nil {
return err
}

if len(aliases) == 0 {
return fmt.Errorf("alias %q not found for index %q", aliasName, indexName)
}

return nil
}
}

const testAccOpensearchIndexUpdateAlias = `
resource "opensearch_index" "test" {
name = "terraform-test-update-alias"
number_of_shards = 1
number_of_replicas = 1
aliases = jsonencode({
"alias1" = {
"is_write_index" = false
}
})
}
`

const testAccOpensearchIndexUpdatedAlias = `
resource "opensearch_index" "test" {
name = "terraform-test-update-alias"
number_of_shards = 1
number_of_replicas = 1
aliases = jsonencode({
"alias2" = {
"is_write_index" = true
}
})
}
`

func TestAccOpensearchIndexUpdateAlias(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: checkOpensearchIndexDestroy,
Steps: []resource.TestStep{
{
Config: testAccOpensearchIndexUpdateAlias,
Check: resource.ComposeTestCheckFunc(
checkOpensearchIndexExists("opensearch_index.test"),
checkOpensearchAliasExists("terraform-test-update-alias", "alias1"),
),
},
{
Config: testAccOpensearchIndexUpdatedAlias,
Check: resource.ComposeTestCheckFunc(
checkOpensearchIndexExists("opensearch_index.test"),
checkOpensearchAliasExists("terraform-test-update-alias", "alias2"),
),
},
},
})
}
func TestAccOpensearchIndexWithAliasAndDelete(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: checkOpensearchAliasDeleted("terraform-test-with-alias", "alias1"),
Steps: []resource.TestStep{
{
Config: testAccOpensearchIndexWithAlias,
Check: resource.ComposeTestCheckFunc(
checkOpensearchIndexExists("opensearch_index.test"),
checkOpensearchAliasExists("terraform-test-with-alias", "alias1"),
),
},
{
ResourceName: "opensearch_index.test",
ImportState: true,
ImportStateId: "terraform-test-with-alias",
ImportStateVerify: true,
Destroy: true,
ImportStateVerifyIgnore: []string{
"aliases", // not handled by this provider
"force_destroy", // not returned from the API
},
},
},
})
}

func checkOpensearchAliasDeleted(indexName, aliasName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
osClient, err := getClient(testAccProvider.Meta().(*ProviderConf))
if err != nil {
return err
}

// Check if the alias no longer exists for the index
aliases, err := osClient.CatAliases().Alias(aliasName).Do(context.TODO())
if err != nil {
return err
}

if len(aliases) > 0 {
return fmt.Errorf("alias %q still exists for index %q", aliasName, indexName)
}

return nil
}
}

0 comments on commit 790834e

Please sign in to comment.