Skip to content

Don't populate settings during read #779

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 19, 2024
Merged
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
7 changes: 5 additions & 2 deletions internal/clients/elasticsearch/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,11 @@ func GetIndex(ctx context.Context, apiClient *clients.ApiClient, name string) (*
return nil, diags
}

index := indices[name]
return &index, diags
if index, ok := indices[name]; ok {
return &index, nil
}

return nil, nil
}

func GetIndices(ctx context.Context, apiClient *clients.ApiClient, name string) (map[string]models.Index, fwdiags.Diagnostics) {
Expand Down
51 changes: 51 additions & 0 deletions internal/elasticsearch/index/index/acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,25 @@ func TestAccResourceIndexSettings(t *testing.T) {
})
}

func TestAccResourceIndexWithTemplate(t *testing.T) {
indexName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum)

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
CheckDestroy: checkResourceIndexDestroy,
ProtoV6ProviderFactories: acctest.Providers,
Steps: []resource.TestStep{
{
Config: testAccResourceIndexWithTemplate(indexName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("elasticstack_elasticsearch_index.test", "name", indexName),
resource.TestCheckNoResourceAttr("elasticstack_elasticsearch_index.test", "default_pipeline"),
),
},
},
})
}

func TestAccResourceIndexRemovingField(t *testing.T) {
indexName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum)

Expand Down Expand Up @@ -450,6 +469,38 @@ resource "elasticstack_elasticsearch_index" "test_settings_removing_field" {
`, name)
}

func testAccResourceIndexWithTemplate(name string) string {
return fmt.Sprintf(`
provider "elasticstack" {
elasticsearch {}
}

resource "elasticstack_elasticsearch_index_template" "test" {
name = "%s"
index_patterns = ["%s"]
template {
settings = jsonencode({
default_pipeline = ".fleet_final_pipeline-1"
lifecycle = { name = ".monitoring-8-ilm-policy" }
})
}
}

resource "elasticstack_elasticsearch_index" "test" {
name = "%s"
deletion_protection = false
alias {
name = "%s-alias"
is_write_index = true
}
lifecycle {
ignore_changes = [mappings]
}
depends_on = [elasticstack_elasticsearch_index_template.test]
}
`, name, name, name, name)
}

func checkResourceIndexDestroy(s *terraform.State) error {
client, err := clients.NewAcceptanceTestingClient()
if err != nil {
Expand Down
149 changes: 0 additions & 149 deletions internal/elasticsearch/index/index/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/json"
"fmt"
"reflect"
"strconv"
"strings"

"github.com/elastic/terraform-provider-elasticstack/internal/clients"
Expand Down Expand Up @@ -223,141 +222,6 @@ func aliasesFromAPI(ctx context.Context, apiModel models.Index) (basetypes.SetVa
}

func setSettingsFromAPI(ctx context.Context, model *tfModel, apiModel models.Index) diag.Diagnostics {
modelType := reflect.TypeOf(*model)

for _, key := range dynamicSettingsKeys {
settingsValue, ok := apiModel.Settings["index."+key]
var tfValue attr.Value
if !ok {
continue
}

tfFieldKey := convertSettingsKeyToTFFieldKey(key)
value, ok := model.getFieldValueByTagValue(tfFieldKey, modelType)
if !ok {
return diag.Diagnostics{
diag.NewErrorDiagnostic(
"failed to find setting value",
fmt.Sprintf("expected setting with key %s", tfFieldKey),
),
}
}

switch a := value.(type) {
case types.String:
settingStr, ok := settingsValue.(string)
if !ok {
return diag.Diagnostics{
diag.NewErrorDiagnostic(
"failed to convert setting to string",
fmt.Sprintf("expected setting to be a string but got %t", settingsValue),
)}
}
tfValue = basetypes.NewStringValue(settingStr)
case types.Bool:
settingBool, ok := settingsValue.(bool)
if !ok {
return diag.Diagnostics{
diag.NewErrorDiagnostic(
"failed to convert setting to bool",
fmt.Sprintf("expected setting to be a bool but got %t", settingsValue),
)}
}
tfValue = basetypes.NewBoolValue(settingBool)
case types.Int64:
if settingStr, ok := settingsValue.(string); ok {
settingInt, err := strconv.Atoi(settingStr)
if err != nil {
return diag.Diagnostics{
diag.NewErrorDiagnostic(
"failed to convert setting to int",
fmt.Sprintf("expected setting to be an int but it was a string. Attempted to parse it but got %s", err.Error()),
),
}
}

settingsValue = int64(settingInt)
}

settingInt, ok := settingsValue.(int64)
if !ok {
return diag.Diagnostics{
diag.NewErrorDiagnostic(
"failed to convert setting to int",
fmt.Sprintf("expected setting to be a int but got %t", settingsValue),
)}
}
tfValue = basetypes.NewInt64Value(settingInt)
case types.List:
elemType := a.ElementType(ctx)
if elemType != types.StringType {
return diag.Diagnostics{
diag.NewErrorDiagnostic(
"expected list of string",
fmt.Sprintf("expected list element type to be string but got %s", elemType),
),
}
}

elems, ok := settingsValue.([]interface{})
if !ok {
return diag.Diagnostics{
diag.NewErrorDiagnostic(
"failed to convert setting to []string",
fmt.Sprintf("expected setting to be a []string but got %#v", settingsValue),
)}
}

var diags diag.Diagnostics
tfValue, diags = basetypes.NewListValueFrom(ctx, basetypes.StringType{}, elems)
if diags.HasError() {
return diags
}
case types.Set:
elemType := a.ElementType(ctx)
if elemType != types.StringType {
return diag.Diagnostics{
diag.NewErrorDiagnostic(
"expected set of string",
fmt.Sprintf("expected set element type to be string but got %s", elemType),
),
}
}

elems, ok := settingsValue.([]interface{})
if !ok {
return diag.Diagnostics{
diag.NewErrorDiagnostic(
"failed to convert setting to []string",
fmt.Sprintf("expected setting to be a thing []string but got %#v", settingsValue),
)}
}

var diags diag.Diagnostics
tfValue, diags = basetypes.NewSetValueFrom(ctx, basetypes.StringType{}, elems)
if diags.HasError() {
return diags
}
default:
return diag.Diagnostics{
diag.NewErrorDiagnostic(
"unknown value type",
fmt.Sprintf("unknown index setting value type %s", a.Type(ctx)),
),
}
}

ok = model.setFieldValueByTagValue(tfFieldKey, modelType, tfValue)
if !ok {
return diag.Diagnostics{
diag.NewErrorDiagnostic(
"failed to find setting value",
fmt.Sprintf("expected setting with key %s", tfFieldKey),
),
}
}
}

settingsBytes, err := json.Marshal(apiModel.Settings)
if err != nil {
return diag.Diagnostics{
Expand Down Expand Up @@ -569,19 +433,6 @@ func (model tfModel) toIndexSettings(ctx context.Context) (map[string]interface{
return settings, nil
}

func (model *tfModel) setFieldValueByTagValue(tagName string, t reflect.Type, value attr.Value) bool {
numField := t.NumField()
for i := 0; i < numField; i++ {
field := t.Field(i)
if field.Tag.Get("tfsdk") == tagName {
reflect.ValueOf(model).Elem().Field(i).Set(reflect.ValueOf(value))
return true
}
}

return false
}

func (model tfModel) getFieldValueByTagValue(tagName string, t reflect.Type) (attr.Value, bool) {
numField := t.NumField()
for i := 0; i < numField; i++ {
Expand Down
58 changes: 39 additions & 19 deletions internal/elasticsearch/index/index/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,19 @@ import (
"github.com/elastic/terraform-provider-elasticstack/internal/elasticsearch/index"
providerschema "github.com/elastic/terraform-provider-elasticstack/internal/schema"
"github.com/elastic/terraform-provider-elasticstack/internal/utils/customtypes"
"github.com/elastic/terraform-provider-elasticstack/internal/utils/planmodifiers"
"github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
Expand Down Expand Up @@ -58,31 +57,46 @@ func getSchema() schema.Schema {
Description: "Value used to route indexing operations to a specific shard. If specified, this overwrites the `routing` value for indexing operations.",
Optional: true,
Computed: true,
Default: stringdefault.StaticString(""),
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
planmodifiers.StringUseDefaultIfUnknown(""),
},
},
"is_hidden": schema.BoolAttribute{
Description: "If true, the alias is hidden.",
Optional: true,
Computed: true,
Default: booldefault.StaticBool(false),
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
planmodifiers.BoolUseDefaultIfUnknown(false),
},
},
"is_write_index": schema.BoolAttribute{
Description: "If true, the index is the write index for the alias.",
Optional: true,
Computed: true,
Default: booldefault.StaticBool(false),
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
planmodifiers.BoolUseDefaultIfUnknown(false),
},
},
"routing": schema.StringAttribute{
Description: "Value used to route indexing and search operations to a specific shard.",
Optional: true,
Computed: true,
Default: stringdefault.StaticString(""),
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
planmodifiers.StringUseDefaultIfUnknown(""),
},
},
"search_routing": schema.StringAttribute{
Description: "Value used to route search operations to a specific shard. If specified, this overwrites the routing value for search operations.",
Optional: true,
Computed: true,
Default: stringdefault.StaticString(""),
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
planmodifiers.StringUseDefaultIfUnknown(""),
},
},
},
},
Expand Down Expand Up @@ -216,10 +230,6 @@ func getSchema() schema.Schema {
"number_of_replicas": schema.Int64Attribute{
Description: "Number of shard replicas.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Int64{
int64planmodifier.UseStateForUnknown(),
},
},
"auto_expand_replicas": schema.StringAttribute{
Description: "Set the number of replicas to the node count in the cluster. Set to a dash delimited lower and upper bound (e.g. 0-5) or use all for the upper bound (e.g. 0-all)",
Expand Down Expand Up @@ -457,8 +467,8 @@ func getSchema() schema.Schema {
Validators: []validator.String{
index.StringIsJSONObject{},
},
Default: stringdefault.StaticString("{}"),
PlanModifiers: []planmodifier.String{
planmodifiers.StringUseDefaultIfUnknown("{}"),
mappingsPlanModifier{},
},
},
Expand All @@ -471,34 +481,44 @@ func getSchema() schema.Schema {
"deletion_protection": schema.BoolAttribute{
Optional: true,
Computed: true,
Default: booldefault.StaticBool(true),
Description: "Whether to allow Terraform to destroy the index. Unless this field is set to false in Terraform state, a terraform destroy or terraform apply command that deletes the instance will fail.",
PlanModifiers: []planmodifier.Bool{
planmodifiers.BoolUseDefaultIfUnknown(true),
},
},
"include_type_name": schema.BoolAttribute{
Description: "If true, a mapping type is expected in the body of mappings. Defaults to false. Supported for Elasticsearch 7.x.",
Optional: true,
Computed: true,
Default: booldefault.StaticBool(false),
PlanModifiers: []planmodifier.Bool{
planmodifiers.BoolUseDefaultIfUnknown(false),
},
},
"wait_for_active_shards": schema.StringAttribute{
Description: "The number of shard copies that must be active before proceeding with the operation. Set to `all` or any positive integer up to the total number of shards in the index (number_of_replicas+1). Default: `1`, the primary shard. This value is ignored when running against Serverless projects.",
Optional: true,
Computed: true,
Default: stringdefault.StaticString("1"),
PlanModifiers: []planmodifier.String{
planmodifiers.StringUseDefaultIfUnknown("1"),
},
},
"master_timeout": schema.StringAttribute{
Description: "Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and returns an error. Defaults to `30s`. This value is ignored when running against Serverless projects.",
Optional: true,
Computed: true,
Default: stringdefault.StaticString("30s"),
CustomType: customtypes.DurationType{},
PlanModifiers: []planmodifier.String{
planmodifiers.StringUseDefaultIfUnknown("30s"),
},
CustomType: customtypes.DurationType{},
},
"timeout": schema.StringAttribute{
Description: "Period to wait for a response. If no response is received before the timeout expires, the request fails and returns an error. Defaults to `30s`.",
Optional: true,
Computed: true,
Default: stringdefault.StaticString("30s"),
CustomType: customtypes.DurationType{},
PlanModifiers: []planmodifier.String{
planmodifiers.StringUseDefaultIfUnknown("30s"),
},
CustomType: customtypes.DurationType{},
},
},
}
Expand Down
Loading
Loading