Skip to content

feat: add ML calendar and calendar event resources#1969

Open
edsavage wants to merge 9 commits into
elastic:mainfrom
edsavage:feat/ml-calendar
Open

feat: add ML calendar and calendar event resources#1969
edsavage wants to merge 9 commits into
elastic:mainfrom
edsavage:feat/ml-calendar

Conversation

@edsavage
Copy link
Copy Markdown
Contributor

@edsavage edsavage commented Mar 23, 2026

Summary

  • Add elasticstack_elasticsearch_ml_calendar resource for managing ML calendars and job associations
  • Add elasticstack_elasticsearch_ml_calendar_event resource for managing individual scheduled events with RFC3339 times
  • Both resources support import, follow Plugin Framework patterns, and include full test suites

Changelog

Customer impact: enhancement
Summary: Add elasticstack_elasticsearch_ml_calendar and elasticstack_elasticsearch_ml_calendar_event resources for managing Elasticsearch ML calendars, scheduled events, and job associations in Terraform.

Details

Calendar resource: Creates/deletes via PUT/DELETE calendar API. Updates job associations in-place by diffing job_ids and calling individual PutCalendarJob/DeleteCalendarJob endpoints. description requires replacement (PUT is create-only).

Calendar event resource: Creates via POST calendar events API, deletes via DELETE. No update API exists — all attributes use RequiresReplace. Server-generated event_id is discovered by diffing events before/after creation.

Test plan

  • Unit tests: 16 cases covering model conversions, null/empty handling, composite ID parsing
  • Acceptance tests: 5 cases (CRUD lifecycle, no-jobs, import for both resources)
  • make build passes (including doc generation)

Made with Cursor

Note

Add elasticstack_elasticsearch_ml_calendar and elasticstack_elasticsearch_ml_calendar_event Terraform resources

  • Adds two new Terraform resources for managing Elasticsearch ML anomaly detection calendars and their associated scheduled events.
  • The calendar resource supports create, read, update (job association reconciliation), delete, and import; the calendar event resource supports create, read, delete, and import (update requires replacement).
  • Calendar events are identified by a composite ID of <cluster_uuid>/<calendar_id>/<event_id>; event IDs are assigned by Elasticsearch and discovered by diffing pre/post-create event lists.
  • Time fields (start_time, end_time) use RFC3339 strings in Terraform state and are converted to/from epoch milliseconds for the API.
  • Both resources are registered in provider/plugin_framework.go and include acceptance tests and generated docs.
📊 Macroscope summarized 5a294b1. 29 files reviewed, 5 issues evaluated, 0 issues filtered, 1 comment posted (Automatic summaries will resume when PR exits draft mode or review begins).

🗂️ Filtered Issues

Comment thread internal/elasticsearch/ml/calendar/update.go Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

PR Changelog Check passed — the ## Changelog section looks good.

edsavage and others added 5 commits May 8, 2026 13:38
Add two new Terraform resources for managing Elasticsearch ML calendars:

- `elasticstack_elasticsearch_ml_calendar` — manages calendar lifecycle
  and job associations via individual PutCalendarJob/DeleteCalendarJob
  endpoints for in-place job_ids updates.
- `elasticstack_elasticsearch_ml_calendar_event` — manages individual
  scheduled events with RFC3339 time handling and server-generated
  event IDs. All attributes require replacement (no update API).

Both resources support import and follow the existing Plugin Framework
patterns. Includes requirements doc, unit tests (16 cases), acceptance
tests (5 cases), and generated documentation.

Made-with: Cursor
Replace defer with immediate Close() calls inside the job add/remove
loops to avoid keeping all response bodies open until function return.

Made-with: Cursor
- Break long lines in schema descriptions to stay under 200 char limit (lll)
- Rename exported types to avoid stuttering (revive): CalendarTFModel→TFModel,
  CalendarCreateAPIModel→CreateAPIModel, CalendarAPIModel→APIModel
- Fix gofmt alignment after renames

Made-with: Cursor
- Use ElasticsearchResource envelope, scoped client, and Ml typed APIs for
  calendar and calendar_event.
- Import state sets resource id attributes; composite IDs support nested
  calendar_id/event_id segments.
- Regenerate resource docs; note new resources in CHANGELOG.

Co-authored-by: Cursor <[email protected]>
@edsavage edsavage force-pushed the feat/ml-calendar branch from 6fd960f to 959023d Compare May 8, 2026 02:00
@edsavage edsavage changed the title WIP: feat: add ML calendar and calendar event resources feat: add ML calendar and calendar event resources May 8, 2026
@edsavage edsavage marked this pull request as ready for review May 8, 2026 02:05
Copilot AI review requested due to automatic review settings May 8, 2026 02:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds two new Terraform Plugin Framework resources to manage Elasticsearch ML anomaly detection calendars and their scheduled events, including provider registration, docs, and test coverage.

Changes:

  • Register new ML calendar and calendar event resources in the provider.
  • Implement elasticstack_elasticsearch_ml_calendar with CRUD + in-place job association reconciliation on update.
  • Implement elasticstack_elasticsearch_ml_calendar_event with create/read/delete + composite IDs and RFC3339 time handling, plus unit/acceptance tests and generated docs.

Reviewed changes

Copilot reviewed 30 out of 30 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
provider/plugin_framework.go Registers the new ML calendar and calendar event resources.
internal/entitycore/resource_envelope.go Adjusts Elasticsearch envelope ID parsing to support resource IDs that may contain slashes.
internal/clients/api_client.go Adds composite-ID parsing variant that splits only on the first / for Elasticsearch resources.
internal/elasticsearch/ml/calendar/resource.go Introduces the ML calendar resource wrapper and import handling.
internal/elasticsearch/ml/calendar/schema.go Defines calendar schema (calendar_id, description, job_ids) and validation.
internal/elasticsearch/ml/calendar/models.go Adds TF/API models and mapping logic (including null/empty handling).
internal/elasticsearch/ml/calendar/create.go Implements calendar create via PUT calendar API and sets composite id.
internal/elasticsearch/ml/calendar/read.go Implements calendar read via GetCalendars and drift removal behavior.
internal/elasticsearch/ml/calendar/update.go Implements update to reconcile job_ids associations via add/remove job endpoints.
internal/elasticsearch/ml/calendar/delete.go Implements calendar delete via DeleteCalendar with 404 idempotency.
internal/elasticsearch/ml/calendar/models_test.go Unit tests for calendar model conversions and null/empty semantics.
internal/elasticsearch/ml/calendar/acc_test.go Acceptance tests for calendar CRUD/update, no-jobs behavior, and import.
internal/elasticsearch/ml/calendar/testdata/TestAccResourceMLCalendar/create/calendar.tf Acceptance test config for calendar create case.
internal/elasticsearch/ml/calendar/testdata/TestAccResourceMLCalendar/update/calendar.tf Acceptance test config for calendar update (job association) case.
internal/elasticsearch/ml/calendar/testdata/TestAccResourceMLCalendarNoJobs/create/calendar.tf Acceptance test config for calendar with no jobs set.
internal/elasticsearch/ml/calendar/testdata/TestAccResourceMLCalendarImport/create/calendar.tf Acceptance test config for calendar import scenario.
internal/elasticsearch/ml/calendar_event/resource.go Introduces calendar event resource with custom Create/Update and import handling.
internal/elasticsearch/ml/calendar_event/schema.go Defines calendar event schema with RFC3339 time custom types and replace semantics.
internal/elasticsearch/ml/calendar_event/models.go Adds TF/API models and time conversions (RFC3339 ↔ epoch millis).
internal/elasticsearch/ml/calendar_event/create.go Implements event creation via PostCalendarEvents and discovers server-generated event_id.
internal/elasticsearch/ml/calendar_event/read.go Implements event read by listing events and locating the matching event_id.
internal/elasticsearch/ml/calendar_event/delete.go Implements event delete via DeleteCalendarEvent with 404 idempotency.
internal/elasticsearch/ml/calendar_event/models_test.go Unit tests for time conversions and composite ID parsing helpers.
internal/elasticsearch/ml/calendar_event/acc_test.go Acceptance tests for calendar event create and import flows.
internal/elasticsearch/ml/calendar_event/testdata/TestAccResourceMLCalendarEvent/create/calendar_event.tf Acceptance test config for event creation.
internal/elasticsearch/ml/calendar_event/testdata/TestAccResourceMLCalendarEventImport/create/calendar_event.tf Acceptance test config for event import scenario.
docs/resources/elasticsearch_ml_calendar.md Generated docs for the ML calendar resource schema.
docs/resources/elasticsearch_ml_calendar_event.md Generated docs for the ML calendar event resource schema.
dev-docs/requirements/elasticsearch/ml/calendar.md Adds implementation requirements/spec for both new resources.
CHANGELOG.md Adds changelog entry for the two new ML resources (and normalizes formatting in the edited section).

Comment thread internal/elasticsearch/ml/calendar_event/schema.go
Comment thread internal/elasticsearch/ml/calendar_event/schema.go
Comment thread internal/elasticsearch/ml/calendar_event/create.go
Comment thread internal/elasticsearch/ml/calendar_event/models.go Outdated
edsavage and others added 3 commits May 8, 2026 14:16
…ation)

- Align calendar_id validators with ml_calendar (length + regex).
- Add ValidateConfig so end_time must be strictly after start_time at plan time.
- Regenerate resource documentation.

Co-authored-by: Cursor <[email protected]>
PostCalendarEventsRequest/Response and GetCalendarEventsResponse were
leftover from the low-level client; create/read use typed API structs.

Co-authored-by: Cursor <[email protected]>
- Fail if listing events before POST fails (no silent empty snapshot).
- Prefer event_id from PostCalendarEvents response when present.
- On list diff, disambiguate multiple new events via description and times.
- Add tests for time coercion and plan matching helpers.

Co-authored-by: Cursor <[email protected]>
@edsavage edsavage added enhancement New feature or request Elasticsearch Elasticsearch related APIs go Pull requests that update Go code labels May 8, 2026
Drop the old dev-docs requirements artifact now that OpenSpec is the canonical requirements source.

Co-authored-by: Cursor <[email protected]>
Copy link
Copy Markdown
Contributor

Copilot AI left a 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 32 out of 32 changed files in this pull request and generated 4 comments.

Comment on lines +87 to +96
// The API returns epoch milliseconds as float64 (JSON number decoded via any).
startMillis, ok := apiModel.StartTime.(float64)
if !ok {
diags.AddError("Invalid start_time format", "Expected epoch milliseconds as a number from the API")
return diags
}
endMillis, ok := apiModel.EndTime.(float64)
if !ok {
diags.AddError("Invalid end_time format", "Expected epoch milliseconds as a number from the API")
return diags
Comment on lines +82 to +104
res, err := typedClient.Ml.GetCalendarEvents(calendarID).Size(10000).Do(ctx)
if err != nil {
var esErr *types.ElasticsearchError
if errors.As(err, &esErr) && esErr.Status == 404 {
return state, false, nil
}
diags.AddError("Failed to get ML calendar events", fmt.Sprintf("Unable to get ML calendar events for calendar %s — %s", calendarID, err.Error()))
return state, false, diags
}

for _, event := range res.Events {
if event.EventId == nil || *event.EventId != eventID {
continue
}
diags.Append(state.fromAPIModel(ctx, calendarEventTypedToAPI(&event))...)
if diags.HasError() {
return state, false, diags
}
tflog.Debug(ctx, fmt.Sprintf("Successfully read ML calendar event %s from calendar: %s", eventID, calendarID))
return state, true, diags
}

return state, false, nil
Comment on lines +95 to +103
existingIDs := make(map[string]struct{})
preRes, err := typedClient.Ml.GetCalendarEvents(calendarID).Size(10000).Do(ctx)
if err != nil {
diags.AddError(
"Failed to list calendar events before create",
fmt.Sprintf("Cannot snapshot existing event IDs for calendar %s — %s", calendarID, err.Error()),
)
return plan, diags
}

if apiModel.Description != "" {
m.Description = types.StringValue(apiModel.Description)
} else {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Elasticsearch Elasticsearch related APIs enhancement New feature or request go Pull requests that update Go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants