Skip to content
Open
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
12 changes: 5 additions & 7 deletions docs/resources/elasticsearch_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,14 @@ provider "elasticstack" {
resource "elasticstack_elasticsearch_index" "my_index" {
name = "my-index"

alias {
alias = [{
name = "my_alias_1"
}

alias {
}, {
name = "my_alias_2"
filter = jsonencode({
term = { "user.id" = "developer" }
})
}
}]

mappings = jsonencode({
properties = {
Expand Down Expand Up @@ -60,7 +58,7 @@ resource "elasticstack_elasticsearch_index" "my_index" {

### Optional

- `alias` (Block Set) Aliases for the index. (see [below for nested schema](#nestedblock--alias))
- `alias` (Attributes Set) Aliases for the index. (see [below for nested schema](#nestedatt--alias))
- `analysis_analyzer` (String) A JSON string describing the analyzers applied to the index.
- `analysis_char_filter` (String) A JSON string describing the char_filters applied to the index.
- `analysis_filter` (String) A JSON string describing the filters applied to the index.
Expand Down Expand Up @@ -136,7 +134,7 @@ resource "elasticstack_elasticsearch_index" "my_index" {
- `id` (String) Internal identifier of the resource
- `settings_raw` (String) All raw settings fetched from the cluster.

<a id="nestedblock--alias"></a>
<a id="nestedatt--alias"></a>
### Nested Schema for `alias`

Required:
Expand Down
61 changes: 61 additions & 0 deletions docs/resources/elasticsearch_index_alias.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@

---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "elasticstack_elasticsearch_index_alias Resource - terraform-provider-elasticstack"
subcategory: "Index"
description: |-
Manages an Elasticsearch alias. See the alias documentation https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html for more details.
---

# elasticstack_elasticsearch_index_alias (Resource)

Manages an Elasticsearch alias. See the [alias documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html) for more details.



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `name` (String) The alias name.

### Optional

- `read_indices` (Attributes Set) Set of read indices for the alias. (see [below for nested schema](#nestedatt--read_indices))
- `write_index` (Attributes) The write index for the alias. Only one write index is allowed per alias. (see [below for nested schema](#nestedatt--write_index))

### Read-Only

- `id` (String) Generated ID of the alias resource.

<a id="nestedatt--read_indices"></a>
### Nested Schema for `read_indices`

Required:

- `name` (String) Name of the read index.

Optional:

- `filter` (String) Query used to limit documents the alias can access.
- `index_routing` (String) Value used to route indexing operations to a specific shard.
- `is_hidden` (Boolean) If true, the alias is hidden.
- `routing` (String) Value used to route indexing and search operations to a specific shard.
- `search_routing` (String) Value used to route search operations to a specific shard.


<a id="nestedatt--write_index"></a>
### Nested Schema for `write_index`

Required:

- `name` (String) Name of the write index.

Optional:

- `filter` (String) Query used to limit documents the alias can access.
- `index_routing` (String) Value used to route indexing operations to a specific shard.
- `is_hidden` (Boolean) If true, the alias is hidden.
- `routing` (String) Value used to route indexing and search operations to a specific shard.
- `search_routing` (String) Value used to route search operations to a specific shard.
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@ provider "elasticstack" {
resource "elasticstack_elasticsearch_index" "my_index" {
name = "my-index"

alias {
alias = [{
name = "my_alias_1"
}

alias {
}, {
name = "my_alias_2"
filter = jsonencode({
term = { "user.id" = "developer" }
})
}
}]

mappings = jsonencode({
properties = {
Expand Down
127 changes: 127 additions & 0 deletions internal/clients/elasticsearch/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,133 @@ func DeleteDataStreamLifecycle(ctx context.Context, apiClient *clients.ApiClient
return nil
}

func GetAlias(ctx context.Context, apiClient *clients.ApiClient, aliasName string) (map[string]models.Index, fwdiags.Diagnostics) {
esClient, err := apiClient.GetESClient()
if err != nil {
return nil, fwdiags.Diagnostics{
fwdiags.NewErrorDiagnostic(err.Error(), err.Error()),
}
}

res, err := esClient.Indices.GetAlias(
esClient.Indices.GetAlias.WithName(aliasName),
esClient.Indices.GetAlias.WithContext(ctx),
)
if err != nil {
return nil, fwdiags.Diagnostics{
fwdiags.NewErrorDiagnostic(err.Error(), err.Error()),
}
}
defer res.Body.Close()

if res.StatusCode == http.StatusNotFound {
return nil, nil
}

diags := diagutil.CheckErrorFromFW(res, fmt.Sprintf("Unable to get alias '%s'", aliasName))
if diags.HasError() {
return nil, diags
}

indices := make(map[string]models.Index)
if err := json.NewDecoder(res.Body).Decode(&indices); err != nil {
return nil, fwdiags.Diagnostics{
fwdiags.NewErrorDiagnostic(err.Error(), err.Error()),
}
}

return indices, nil
}

// AliasAction represents a single action in an atomic alias update operation
type AliasAction struct {
Type string // "add" or "remove"
Index string
Alias string
IsWriteIndex bool
Filter map[string]interface{}
IndexRouting string
IsHidden bool
Routing string
SearchRouting string
}

// UpdateAliasesAtomic performs atomic alias updates using multiple actions
func UpdateAliasesAtomic(ctx context.Context, apiClient *clients.ApiClient, actions []AliasAction) fwdiags.Diagnostics {
esClient, err := apiClient.GetESClient()
if err != nil {
return fwdiags.Diagnostics{
fwdiags.NewErrorDiagnostic(err.Error(), err.Error()),
}
}

var aliasActions []map[string]interface{}

for _, action := range actions {
switch action.Type {
case "remove":
aliasActions = append(aliasActions, map[string]interface{}{
"remove": map[string]interface{}{
"index": action.Index,
"alias": action.Alias,
},
})
case "add":
addDetails := map[string]interface{}{
"index": action.Index,
"alias": action.Alias,
}

if action.IsWriteIndex {
addDetails["is_write_index"] = true
}
if action.Filter != nil {
addDetails["filter"] = action.Filter
}
if action.IndexRouting != "" {
addDetails["index_routing"] = action.IndexRouting
}
if action.SearchRouting != "" {
addDetails["search_routing"] = action.SearchRouting
}
if action.Routing != "" {
addDetails["routing"] = action.Routing
}
if action.IsHidden {
addDetails["is_hidden"] = action.IsHidden
}

aliasActions = append(aliasActions, map[string]interface{}{
"add": addDetails,
})
}
}

requestBody := map[string]interface{}{
"actions": aliasActions,
}

aliasBytes, err := json.Marshal(requestBody)
if err != nil {
return fwdiags.Diagnostics{
fwdiags.NewErrorDiagnostic(err.Error(), err.Error()),
}
}

res, err := esClient.Indices.UpdateAliases(
bytes.NewReader(aliasBytes),
esClient.Indices.UpdateAliases.WithContext(ctx),
)
if err != nil {
return fwdiags.Diagnostics{
fwdiags.NewErrorDiagnostic(err.Error(), err.Error()),
}
}
defer res.Body.Close()

return diagutil.CheckErrorFromFW(res, "Unable to update aliases atomically")
}

func PutIngestPipeline(ctx context.Context, apiClient *clients.ApiClient, pipeline *models.IngestPipeline) diag.Diagnostics {
var diags diag.Diagnostics
pipelineBytes, err := json.Marshal(pipeline)
Expand Down
Loading
Loading