-
Notifications
You must be signed in to change notification settings - Fork 123
fix(ml): anomaly_detection_job import/refresh mismatch #1550
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
base: main
Are you sure you want to change the base?
Conversation
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).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| raw := req.ID | ||
| parts := strings.Split(raw, "/") | ||
| jobID := parts[len(parts)-1] |
Copilot
AI
Dec 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ImportState function does not validate the import ID format before splitting. If req.ID is empty or does not contain the expected format, this could result in setting an empty jobID. Consider adding validation to ensure the ID is not empty and optionally check that it matches the expected format (e.g., 'default/<job_id>' or just '<job_id>').
| raw := req.ID | |
| parts := strings.Split(raw, "/") | |
| jobID := parts[len(parts)-1] | |
| raw := req.ID | |
| if strings.TrimSpace(raw) == "" { | |
| resp.Diagnostics.AddError( | |
| "Invalid import ID", | |
| "Import ID cannot be empty. Please provide a valid job ID or 'default/<job_id>'.", | |
| ) | |
| return | |
| } | |
| parts := strings.Split(raw, "/") | |
| jobID := parts[len(parts)-1] | |
| if strings.TrimSpace(jobID) == "" { | |
| resp.Diagnostics.AddError( | |
| "Invalid import ID format", | |
| "Could not extract a valid job ID from the import ID. Please use '<job_id>' or 'default/<job_id>'.", | |
| ) | |
| return | |
| } |
| 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) | ||
| } |
Copilot
AI
Dec 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic for handling untyped zero-value lists is duplicated three times in this file (CategorizationFilters, Influencers, and CustomRules). Consider extracting this into a helper function that takes a list value and element type, returning a properly typed list to reduce duplication and improve maintainability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 to making this reusable somewhere (either in this file or in the typeutil package).
Do we actually need this? I'm fairly sure we haven't added this into other resources which makes me a bit sceptical.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Best I can tell is that, yes, it is needed. Without handling this, I see the following errors :
elasticstack_elasticsearch_ml_anomaly_detection_job.example: Importing from ID "default/example-anomaly-detector"...
elasticstack_elasticsearch_ml_anomaly_detection_job.example: Import prepared!
Prepared elasticstack_elasticsearch_ml_anomaly_detection_job for import
elasticstack_elasticsearch_ml_anomaly_detection_job.example: Refreshing state... [id=default/example-anomaly-detector]
╷
│ Error: Value Conversion Error
│
│ An unexpected error was encountered while verifying an attribute value matched its expected type to prevent unexpected behavior or panics. This is always an
│ error in the provider. Please report the following to the provider developer:
│
│ Expected framework type from provider logic: types.ListType[basetypes.StringType] / underlying type: tftypes.List[tftypes.String]
│ Received framework type from provider logic: types.ListType[!!! MISSING TYPE !!!] / underlying type: tftypes.List[tftypes.DynamicPseudoType]
│ Path: analysis_config.categorization_filters
I'll try and refactor it somewhere more useful !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot open a new pull request to apply changes based on this feedback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
0185df6 from CoPilot seems a reasonable attempt.
tobio
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple of small comments. Can we add an import test step into the existing acceptance tests to verify the import pathway whilst we're here?
| 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) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 to making this reusable somewhere (either in this file or in the typeutil package).
Do we actually need this? I'm fairly sure we haven't added this into other resources which makes me a bit sceptical.
Co-authored-by: Toby Brain <[email protected]>
|
@neiljbrookes I've opened a new pull request, #1559, to work on those changes. Once the pull request is ready, I'll request review from you. |
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.
I have attempted an |
* 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 <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: neiljbrookes <[email protected]>
tobio
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Are you able to add an entry to CHANGELOG.md for this one (sorry I should have picked this up earlier) before we merge it.
…ml_anomaly_detection_job` import, enhancing resilience to sparse state values.
Summary
Fixes
elasticstack_elasticsearch_ml_anomaly_detection_jobimport/refresh mismatch reported in #1549.Background / repro (from #1549)
terraform import elasticstack_elasticsearch_ml_anomaly_detection_job.example default/<job_id>Read).Root cause
analysis_config = nullduring the firstReadafter import.What changed
ImportStatenow sets only identifiers (id+job_id) and normalizes IDs likedefault/<job_id>-><job_id>(the actual Elasticsearch ML job id).analysis_configin the state model is now nullable soreq.State.Get()can succeed immediately after import, allowingReadto fetch and populate the full object from Elasticsearch.analysis_config.categorization_filters,analysis_config.influencers, anddetectors[*].custom_rulesalways return correctly typed list values (e.g.,list(string)/list(object)), avoiding DynamicPseudoType conversion errors when API slices are empty.Behavior after this change
terraform import ... default/<job_id>succeeds.Read) successfully populatesanalysis_config(and other attributes) from Elasticsearch.Testing
go test ./...Fixes #1549.
AI assistance
This change was implemented with the help of an AI coding assistant (Cursor + GPT).