From d522227574a3b3a08a4eef6d914e3f6bbd3538ee Mon Sep 17 00:00:00 2001 From: neiljbrookes Date: Mon, 15 Dec 2025 14:43:54 +0000 Subject: [PATCH 1/6] fix(ml): make anomaly_detection_job import resilient Fixes terraform import/refresh failures for elasticstack_elasticsearch_ml_anomaly_detection_job by keeping ImportState sparse (id/job_id only) and allowing analysis_config to be null during import before Read populates it. Also ensures empty nested lists in analysis_config (e.g. categorization_filters/influencers/custom_rules) are always typed to avoid DynamicPseudoType conversion errors. AI assistance: This change was implemented with the help of an AI coding assistant (Cursor + GPT). --- .../ml/anomaly_detection_job/models_tf.go | 104 +++++++++++------- .../ml/anomaly_detection_job/resource.go | 9 +- 2 files changed, 74 insertions(+), 39 deletions(-) diff --git a/internal/elasticsearch/ml/anomaly_detection_job/models_tf.go b/internal/elasticsearch/ml/anomaly_detection_job/models_tf.go index 08d0097b3..8f304f78d 100644 --- a/internal/elasticsearch/ml/anomaly_detection_job/models_tf.go +++ b/internal/elasticsearch/ml/anomaly_detection_job/models_tf.go @@ -17,23 +17,24 @@ import ( // AnomalyDetectionJobTFModel represents the Terraform resource model for ML anomaly detection jobs type AnomalyDetectionJobTFModel struct { - ID types.String `tfsdk:"id"` - ElasticsearchConnection types.List `tfsdk:"elasticsearch_connection"` - JobID types.String `tfsdk:"job_id"` - Description types.String `tfsdk:"description"` - Groups types.Set `tfsdk:"groups"` - AnalysisConfig AnalysisConfigTFModel `tfsdk:"analysis_config"` - AnalysisLimits types.Object `tfsdk:"analysis_limits"` - DataDescription types.Object `tfsdk:"data_description"` - ModelPlotConfig types.Object `tfsdk:"model_plot_config"` - AllowLazyOpen types.Bool `tfsdk:"allow_lazy_open"` - BackgroundPersistInterval types.String `tfsdk:"background_persist_interval"` - CustomSettings jsontypes.Normalized `tfsdk:"custom_settings"` - DailyModelSnapshotRetentionAfterDays types.Int64 `tfsdk:"daily_model_snapshot_retention_after_days"` - ModelSnapshotRetentionDays types.Int64 `tfsdk:"model_snapshot_retention_days"` - RenormalizationWindowDays types.Int64 `tfsdk:"renormalization_window_days"` - ResultsIndexName types.String `tfsdk:"results_index_name"` - ResultsRetentionDays types.Int64 `tfsdk:"results_retention_days"` + ID types.String `tfsdk:"id"` + ElasticsearchConnection types.List `tfsdk:"elasticsearch_connection"` + JobID types.String `tfsdk:"job_id"` + Description types.String `tfsdk:"description"` + Groups types.Set `tfsdk:"groups"` + // AnalysisConfig is required in configuration, but can be null in state during import. + AnalysisConfig *AnalysisConfigTFModel `tfsdk:"analysis_config"` + AnalysisLimits types.Object `tfsdk:"analysis_limits"` + DataDescription types.Object `tfsdk:"data_description"` + ModelPlotConfig types.Object `tfsdk:"model_plot_config"` + AllowLazyOpen types.Bool `tfsdk:"allow_lazy_open"` + BackgroundPersistInterval types.String `tfsdk:"background_persist_interval"` + CustomSettings jsontypes.Normalized `tfsdk:"custom_settings"` + DailyModelSnapshotRetentionAfterDays types.Int64 `tfsdk:"daily_model_snapshot_retention_after_days"` + ModelSnapshotRetentionDays types.Int64 `tfsdk:"model_snapshot_retention_days"` + RenormalizationWindowDays types.Int64 `tfsdk:"renormalization_window_days"` + ResultsIndexName types.String `tfsdk:"results_index_name"` + ResultsRetentionDays types.Int64 `tfsdk:"results_retention_days"` // Read-only computed fields CreateTime types.String `tfsdk:"create_time"` @@ -124,9 +125,15 @@ func (plan *AnomalyDetectionJobTFModel) toAPIModel(ctx context.Context) (*Anomal apiModel.Groups = groups } + if plan.AnalysisConfig == nil { + diags.AddError("Missing analysis_config", "analysis_config is required") + return nil, diags + } + analysisConfig := plan.AnalysisConfig + // Convert detectors - apiDetectors := make([]DetectorAPIModel, len(plan.AnalysisConfig.Detectors)) - for i, detector := range plan.AnalysisConfig.Detectors { + apiDetectors := make([]DetectorAPIModel, len(analysisConfig.Detectors)) + for i, detector := range analysisConfig.Detectors { apiDetectors[i] = DetectorAPIModel{ Function: detector.Function.ValueString(), FieldName: detector.FieldName.ValueString(), @@ -143,40 +150,40 @@ func (plan *AnomalyDetectionJobTFModel) toAPIModel(ctx context.Context) (*Anomal // Convert influencers var influencers []string - if utils.IsKnown(plan.AnalysisConfig.Influencers) { - d := plan.AnalysisConfig.Influencers.ElementsAs(ctx, &influencers, false) + if utils.IsKnown(analysisConfig.Influencers) { + d := analysisConfig.Influencers.ElementsAs(ctx, &influencers, false) diags.Append(d...) } apiModel.AnalysisConfig = AnalysisConfigAPIModel{ - BucketSpan: plan.AnalysisConfig.BucketSpan.ValueString(), - CategorizationFieldName: plan.AnalysisConfig.CategorizationFieldName.ValueString(), + BucketSpan: analysisConfig.BucketSpan.ValueString(), + CategorizationFieldName: analysisConfig.CategorizationFieldName.ValueString(), Detectors: apiDetectors, Influencers: influencers, - Latency: plan.AnalysisConfig.Latency.ValueString(), - ModelPruneWindow: plan.AnalysisConfig.ModelPruneWindow.ValueString(), - SummaryCountFieldName: plan.AnalysisConfig.SummaryCountFieldName.ValueString(), + Latency: analysisConfig.Latency.ValueString(), + ModelPruneWindow: analysisConfig.ModelPruneWindow.ValueString(), + SummaryCountFieldName: analysisConfig.SummaryCountFieldName.ValueString(), } - if utils.IsKnown(plan.AnalysisConfig.MultivariateByFields) { - apiModel.AnalysisConfig.MultivariateByFields = utils.Pointer(plan.AnalysisConfig.MultivariateByFields.ValueBool()) + if utils.IsKnown(analysisConfig.MultivariateByFields) { + apiModel.AnalysisConfig.MultivariateByFields = utils.Pointer(analysisConfig.MultivariateByFields.ValueBool()) } // Convert categorization filters - if utils.IsKnown(plan.AnalysisConfig.CategorizationFilters) { + if utils.IsKnown(analysisConfig.CategorizationFilters) { var categorizationFilters []string - d := plan.AnalysisConfig.CategorizationFilters.ElementsAs(ctx, &categorizationFilters, false) + d := analysisConfig.CategorizationFilters.ElementsAs(ctx, &categorizationFilters, false) diags.Append(d...) apiModel.AnalysisConfig.CategorizationFilters = categorizationFilters } // Convert per_partition_categorization - if plan.AnalysisConfig.PerPartitionCategorization != nil { + if analysisConfig.PerPartitionCategorization != nil { apiModel.AnalysisConfig.PerPartitionCategorization = &PerPartitionCategorizationAPIModel{ - Enabled: plan.AnalysisConfig.PerPartitionCategorization.Enabled.ValueBool(), + Enabled: analysisConfig.PerPartitionCategorization.Enabled.ValueBool(), } - if utils.IsKnown(plan.AnalysisConfig.PerPartitionCategorization.StopOnWarn) { - apiModel.AnalysisConfig.PerPartitionCategorization.StopOnWarn = utils.Pointer(plan.AnalysisConfig.PerPartitionCategorization.StopOnWarn.ValueBool()) + if utils.IsKnown(analysisConfig.PerPartitionCategorization.StopOnWarn) { + apiModel.AnalysisConfig.PerPartitionCategorization.StopOnWarn = utils.Pointer(analysisConfig.PerPartitionCategorization.StopOnWarn.ValueBool()) } } @@ -331,12 +338,15 @@ func (tfModel *AnomalyDetectionJobTFModel) fromAPIModel(ctx context.Context, api // Helper functions for schema attribute types // Conversion helper methods -func (tfModel *AnomalyDetectionJobTFModel) convertAnalysisConfigFromAPI(ctx context.Context, apiConfig *AnalysisConfigAPIModel, diags *diag.Diagnostics) AnalysisConfigTFModel { +func (tfModel *AnomalyDetectionJobTFModel) convertAnalysisConfigFromAPI(ctx context.Context, apiConfig *AnalysisConfigAPIModel, diags *diag.Diagnostics) *AnalysisConfigTFModel { if apiConfig == nil || apiConfig.BucketSpan == "" { - return AnalysisConfigTFModel{} + return nil } - analysisConfigTF := tfModel.AnalysisConfig + var analysisConfigTF AnalysisConfigTFModel + if tfModel.AnalysisConfig != nil { + analysisConfigTF = *tfModel.AnalysisConfig + } analysisConfigTF.BucketSpan = types.StringValue(apiConfig.BucketSpan) // Convert optional string fields @@ -352,11 +362,23 @@ func (tfModel *AnomalyDetectionJobTFModel) convertAnalysisConfigFromAPI(ctx cont var categorizationFiltersDiags diag.Diagnostics analysisConfigTF.CategorizationFilters, categorizationFiltersDiags = typeutils.NonEmptyListOrDefault(ctx, analysisConfigTF.CategorizationFilters, types.StringType, apiConfig.CategorizationFilters) diags.Append(categorizationFiltersDiags...) + // If the existing value was an untyped zero-value list (common during import), force a typed null list. + if analysisConfigTF.CategorizationFilters.ElementType(ctx) == nil { + analysisConfigTF.CategorizationFilters = types.ListNull(types.StringType) + } else if _, ok := analysisConfigTF.CategorizationFilters.ElementType(ctx).(basetypes.DynamicType); ok { + analysisConfigTF.CategorizationFilters = types.ListNull(types.StringType) + } // Convert influencers var influencersDiags diag.Diagnostics analysisConfigTF.Influencers, influencersDiags = typeutils.NonEmptyListOrDefault(ctx, analysisConfigTF.Influencers, types.StringType, apiConfig.Influencers) diags.Append(influencersDiags...) + // If the existing value was an untyped zero-value list (common during import), force a typed null list. + if analysisConfigTF.Influencers.ElementType(ctx) == nil { + analysisConfigTF.Influencers = types.ListNull(types.StringType) + } else if _, ok := analysisConfigTF.Influencers.ElementType(ctx).(basetypes.DynamicType); ok { + analysisConfigTF.Influencers = types.ListNull(types.StringType) + } // Convert detectors if len(apiConfig.Detectors) > 0 { @@ -427,6 +449,12 @@ func (tfModel *AnomalyDetectionJobTFModel) convertAnalysisConfigFromAPI(ctx cont var customRulesDiags diag.Diagnostics detectorsTF[i].CustomRules, customRulesDiags = typeutils.NonEmptyListOrDefault(ctx, originalDetector.CustomRules, types.ObjectType{AttrTypes: getCustomRuleAttrTypes()}, apiConfig.Detectors[i].CustomRules) diags.Append(customRulesDiags...) + // If the existing value was an untyped zero-value list (common during import), force a typed null list. + if detectorsTF[i].CustomRules.ElementType(ctx) == nil { + detectorsTF[i].CustomRules = types.ListNull(types.ObjectType{AttrTypes: getCustomRuleAttrTypes()}) + } else if _, ok := detectorsTF[i].CustomRules.ElementType(ctx).(basetypes.DynamicType); ok { + detectorsTF[i].CustomRules = types.ListNull(types.ObjectType{AttrTypes: getCustomRuleAttrTypes()}) + } } analysisConfigTF.Detectors = detectorsTF } @@ -440,7 +468,7 @@ func (tfModel *AnomalyDetectionJobTFModel) convertAnalysisConfigFromAPI(ctx cont analysisConfigTF.PerPartitionCategorization = &perPartitionCategorizationTF } - return analysisConfigTF + return &analysisConfigTF } func (tfModel *AnomalyDetectionJobTFModel) convertDataDescriptionFromAPI(ctx context.Context, apiDataDescription *DataDescriptionAPIModel, diags *diag.Diagnostics) types.Object { diff --git a/internal/elasticsearch/ml/anomaly_detection_job/resource.go b/internal/elasticsearch/ml/anomaly_detection_job/resource.go index e701228c6..1d1620ecc 100644 --- a/internal/elasticsearch/ml/anomaly_detection_job/resource.go +++ b/internal/elasticsearch/ml/anomaly_detection_job/resource.go @@ -2,6 +2,7 @@ package anomaly_detection_job import ( "context" + "strings" "github.com/elastic/terraform-provider-elasticstack/internal/clients" fwdiags "github.com/hashicorp/terraform-plugin-framework/diag" @@ -71,5 +72,11 @@ func (r *anomalyDetectionJobResource) resourceReady(diags *fwdiags.Diagnostics) } func (r *anomalyDetectionJobResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) + // Import is intentionally sparse: only IDs are set. Everything else is populated by Read(). + raw := req.ID + parts := strings.Split(raw, "/") + jobID := parts[len(parts)-1] + + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), jobID)...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("job_id"), jobID)...) } From 177c6eb946aaf64553ad345e97fa6967d323ae1b Mon Sep 17 00:00:00 2001 From: Neil Brookes Date: Tue, 16 Dec 2025 10:33:41 +0000 Subject: [PATCH 2/6] Update internal/elasticsearch/ml/anomaly_detection_job/resource.go Co-authored-by: Toby Brain --- .../ml/anomaly_detection_job/resource.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/internal/elasticsearch/ml/anomaly_detection_job/resource.go b/internal/elasticsearch/ml/anomaly_detection_job/resource.go index 1d1620ecc..9c45e6afb 100644 --- a/internal/elasticsearch/ml/anomaly_detection_job/resource.go +++ b/internal/elasticsearch/ml/anomaly_detection_job/resource.go @@ -73,10 +73,12 @@ func (r *anomalyDetectionJobResource) resourceReady(diags *fwdiags.Diagnostics) func (r *anomalyDetectionJobResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { // Import is intentionally sparse: only IDs are set. Everything else is populated by Read(). - raw := req.ID - parts := strings.Split(raw, "/") - jobID := parts[len(parts)-1] + compID, diags := clients.CompositeIdFromStrFw(req.ID) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), jobID)...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("job_id"), jobID)...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), req.ID)...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("job_id"), compID.ResourceId)...) } From d07ccdabfe4cd181a4401174e5a8a9d49158ac0c Mon Sep 17 00:00:00 2001 From: neiljbrookes Date: Tue, 16 Dec 2025 10:53:13 +0000 Subject: [PATCH 3/6] Remove unused import in anomaly_detection_job resource file --- internal/elasticsearch/ml/anomaly_detection_job/resource.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/elasticsearch/ml/anomaly_detection_job/resource.go b/internal/elasticsearch/ml/anomaly_detection_job/resource.go index 9c45e6afb..a59ec7c9b 100644 --- a/internal/elasticsearch/ml/anomaly_detection_job/resource.go +++ b/internal/elasticsearch/ml/anomaly_detection_job/resource.go @@ -2,7 +2,6 @@ package anomaly_detection_job import ( "context" - "strings" "github.com/elastic/terraform-provider-elasticstack/internal/clients" fwdiags "github.com/hashicorp/terraform-plugin-framework/diag" From 76d4e4bbd82a671b573a3f9f2011187d08d7fde2 Mon Sep 17 00:00:00 2001 From: neiljbrookes Date: Tue, 16 Dec 2025 11:26:39 +0000 Subject: [PATCH 4/6] Add ImportState testing for anomaly_detection_job acceptance tests This update introduces ImportState testing for the elasticstack_elasticsearch_ml_anomaly_detection_job resource, ensuring that the job can be imported correctly with the necessary configuration variables. The test verifies the import functionality and enhances the robustness of the acceptance tests. --- .../ml/anomaly_detection_job/acc_test.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/internal/elasticsearch/ml/anomaly_detection_job/acc_test.go b/internal/elasticsearch/ml/anomaly_detection_job/acc_test.go index 208f32b38..0ea29cad3 100644 --- a/internal/elasticsearch/ml/anomaly_detection_job/acc_test.go +++ b/internal/elasticsearch/ml/anomaly_detection_job/acc_test.go @@ -56,6 +56,17 @@ func TestAccResourceAnomalyDetectionJobBasic(t *testing.T) { resource.TestCheckResourceAttr("elasticstack_elasticsearch_ml_anomaly_detection_job.test", "job_type", "anomaly_detector"), ), }, + // ImportState testing + { + ProtoV6ProviderFactories: acctest.Providers, + ResourceName: "elasticstack_elasticsearch_ml_anomaly_detection_job.test", + ImportState: true, + ImportStateVerify: true, + ConfigDirectory: acctest.NamedTestCaseDirectory("update"), + ConfigVariables: config.Variables{ + "job_id": config.StringVariable(jobID), + }, + }, }, }) } From 0185df6e51b0fc2f13c87ccdfe6fa95da689ac94 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 13:25:11 +0000 Subject: [PATCH 5/6] Extract duplicated list type handling logic into reusable helper (#1559) * Initial plan * Refactor: extract duplicated list type handling into reusable helper function - Created EnsureTypedList helper in typeutils package - Replaced three instances of duplicated logic for handling untyped zero-value lists - Removed unused strings import from resource.go - All three instances (CategorizationFilters, Influencers, CustomRules) now use the centralized helper Co-authored-by: neiljbrookes <851324+neiljbrookes@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: neiljbrookes <851324+neiljbrookes@users.noreply.github.com> --- .../ml/anomaly_detection_job/models_tf.go | 24 +++++-------------- internal/utils/typeutils/list.go | 20 ++++++++++++++++ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/internal/elasticsearch/ml/anomaly_detection_job/models_tf.go b/internal/elasticsearch/ml/anomaly_detection_job/models_tf.go index 8f304f78d..0f58eecb4 100644 --- a/internal/elasticsearch/ml/anomaly_detection_job/models_tf.go +++ b/internal/elasticsearch/ml/anomaly_detection_job/models_tf.go @@ -362,23 +362,15 @@ func (tfModel *AnomalyDetectionJobTFModel) convertAnalysisConfigFromAPI(ctx cont var categorizationFiltersDiags diag.Diagnostics analysisConfigTF.CategorizationFilters, categorizationFiltersDiags = typeutils.NonEmptyListOrDefault(ctx, analysisConfigTF.CategorizationFilters, types.StringType, apiConfig.CategorizationFilters) diags.Append(categorizationFiltersDiags...) - // If the existing value was an untyped zero-value list (common during import), force a typed null list. - if analysisConfigTF.CategorizationFilters.ElementType(ctx) == nil { - analysisConfigTF.CategorizationFilters = types.ListNull(types.StringType) - } else if _, ok := analysisConfigTF.CategorizationFilters.ElementType(ctx).(basetypes.DynamicType); ok { - analysisConfigTF.CategorizationFilters = types.ListNull(types.StringType) - } + // Ensure the list is properly typed (handles untyped zero-value lists from import) + analysisConfigTF.CategorizationFilters = typeutils.EnsureTypedList(ctx, analysisConfigTF.CategorizationFilters, types.StringType) // Convert influencers var influencersDiags diag.Diagnostics analysisConfigTF.Influencers, influencersDiags = typeutils.NonEmptyListOrDefault(ctx, analysisConfigTF.Influencers, types.StringType, apiConfig.Influencers) diags.Append(influencersDiags...) - // If the existing value was an untyped zero-value list (common during import), force a typed null list. - if analysisConfigTF.Influencers.ElementType(ctx) == nil { - analysisConfigTF.Influencers = types.ListNull(types.StringType) - } else if _, ok := analysisConfigTF.Influencers.ElementType(ctx).(basetypes.DynamicType); ok { - analysisConfigTF.Influencers = types.ListNull(types.StringType) - } + // Ensure the list is properly typed (handles untyped zero-value lists from import) + analysisConfigTF.Influencers = typeutils.EnsureTypedList(ctx, analysisConfigTF.Influencers, types.StringType) // Convert detectors if len(apiConfig.Detectors) > 0 { @@ -449,12 +441,8 @@ func (tfModel *AnomalyDetectionJobTFModel) convertAnalysisConfigFromAPI(ctx cont var customRulesDiags diag.Diagnostics detectorsTF[i].CustomRules, customRulesDiags = typeutils.NonEmptyListOrDefault(ctx, originalDetector.CustomRules, types.ObjectType{AttrTypes: getCustomRuleAttrTypes()}, apiConfig.Detectors[i].CustomRules) diags.Append(customRulesDiags...) - // If the existing value was an untyped zero-value list (common during import), force a typed null list. - if detectorsTF[i].CustomRules.ElementType(ctx) == nil { - detectorsTF[i].CustomRules = types.ListNull(types.ObjectType{AttrTypes: getCustomRuleAttrTypes()}) - } else if _, ok := detectorsTF[i].CustomRules.ElementType(ctx).(basetypes.DynamicType); ok { - detectorsTF[i].CustomRules = types.ListNull(types.ObjectType{AttrTypes: getCustomRuleAttrTypes()}) - } + // Ensure the list is properly typed (handles untyped zero-value lists from import) + detectorsTF[i].CustomRules = typeutils.EnsureTypedList(ctx, detectorsTF[i].CustomRules, types.ObjectType{AttrTypes: getCustomRuleAttrTypes()}) } analysisConfigTF.Detectors = detectorsTF } diff --git a/internal/utils/typeutils/list.go b/internal/utils/typeutils/list.go index 0a3715000..87282b33a 100644 --- a/internal/utils/typeutils/list.go +++ b/internal/utils/typeutils/list.go @@ -6,6 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) func NonEmptyListOrDefault[T any](ctx context.Context, original types.List, elemType attr.Type, slice []T) (types.List, diag.Diagnostics) { @@ -15,3 +16,22 @@ func NonEmptyListOrDefault[T any](ctx context.Context, original types.List, elem return types.ListValueFrom(ctx, elemType, slice) } + +// EnsureTypedList converts untyped zero-value lists to properly typed null lists. +// This is commonly needed during import operations where the framework may create +// untyped lists with DynamicPseudoType elements, which causes type conversion errors. +// If the list already has a proper type, it is returned unchanged. +func EnsureTypedList(ctx context.Context, list types.List, elemType attr.Type) types.List { + // Check if the list has no element type (nil) + if list.ElementType(ctx) == nil { + return types.ListNull(elemType) + } + + // Check if the list has a dynamic pseudo type + if _, ok := list.ElementType(ctx).(basetypes.DynamicType); ok { + return types.ListNull(elemType) + } + + // List is already properly typed, return as-is + return list +} From e1dbb86026035cc45ca0e89d503647f0f345dc13 Mon Sep 17 00:00:00 2001 From: neiljbrookes Date: Wed, 17 Dec 2025 15:44:39 +0000 Subject: [PATCH 6/6] Update CHANGELOG.md to include a fix for `elasticstack_elasticsearch_ml_anomaly_detection_job` import, enhancing resilience to sparse state values. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33e50001a..352a5a7f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,7 @@ inputs = { - Fix the enabled property being ignored in `elasticstack_kibana_alerting_rule` ([#1527](https://github.com/elastic/terraform-provider-elasticstack/pull/1527)) - Add `advanced_monitoring_options` to `elasticstack_fleet_agent_policy` to configure HTTP monitoring endpoint and diagnostics settings ([#1537](https://github.com/elastic/terraform-provider-elasticstack/pull/1537)) - Move the `input` block to an `inputs` map in `elasticstack_fleet_integration_policy` ([#1482](https://github.com/elastic/terraform-provider-elasticstack/pull/1482)) +- Fix `elasticstack_elasticsearch_ml_anomaly_detection_job` import to be resilient to sparse state values ## [0.13.1] - 2025-12-12