You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In Terraform configuration, each phase is written as a **single nested block** (for example `hot { ... }`), which corresponds to a one-element list in the provider schema.
47
+
In Terraform configuration, each phase is written as a **`SingleNestedBlock`** (for example `hot { ... }`). State stores that phase as an object-shaped value (or null when absent), not as a single-element list.
48
48
49
49
### Per-phase object (common)
50
50
@@ -56,7 +56,7 @@ Every phase object MAY include:
56
56
57
57
### Allowed nested actions by phase
58
58
59
-
| Phase | Nested action blocks (each is a list with **MaxItems = 1** unless noted) |
59
+
| Phase | Nested action blocks (each is a **`SingleNestedBlock`**) |
Each action below is expressed as Terraform nested block syntax. All such blocks are **optional**; each uses**list** semantics with **max 1** element in practice (`action { ... }` is one list element).
69
+
Each action below is expressed as Terraform nested block syntax. All such blocks are **optional** and use**`SingleNestedBlock`** semantics (`action { ... }`); state stores each declared action as an object, not as a list.
70
70
71
71
```hcl
72
72
# allocate — warm, cold only
@@ -84,8 +84,9 @@ delete {
84
84
}
85
85
86
86
# forcemerge — hot, warm only
87
+
# When the block is omitted, max_num_segments is not required. When the block is declared, max_num_segments is required (object-level AlsoRequires).
87
88
forcemerge {
88
-
max_num_segments = <required, int, >= 1>
89
+
max_num_segments = <optional, int, >= 1> # required when block is present
89
90
index_codec = <optional, string>
90
91
}
91
92
@@ -119,14 +120,16 @@ rollover {
119
120
}
120
121
121
122
# searchable_snapshot — hot, cold, frozen only
123
+
# snapshot_repository required when block is present (object-level AlsoRequires).
122
124
searchable_snapshot {
123
-
snapshot_repository = <required, string>
125
+
snapshot_repository = <optional, string> # required when block is present
@@ -369,3 +374,75 @@ If expansion encounters an action key that is not supported by the provider’s
369
374
- GIVEN an internal expansion path surfaces an unknown action name
370
375
- WHEN the policy is expanded
371
376
- THEN the provider SHALL return a diagnostic
377
+
378
+
### Requirement: Single nested blocks for phases and actions (REQ-020)
379
+
380
+
The resource SHALL model each of the phase blocks `hot`, `warm`, `cold`, `frozen`, and `delete` as a **Plugin Framework `SingleNestedBlock`** (at most one block per phase in configuration; state stores a single nested object or null when absent), not as a list nested block with a maximum length of one.
381
+
382
+
Each ILM action block allowed under a phase (for example `set_priority`, `rollover`, `forcemerge`, `searchable_snapshot`, `wait_for_snapshot`, `delete`, and other actions defined by the provider schema) SHALL likewise be modeled as a **`SingleNestedBlock`**.
383
+
384
+
The **`elasticsearch_connection`** block SHALL remain a **list nested block** as provided by the shared provider connection schema.
385
+
386
+
#### Scenario: Phase block cardinality
387
+
388
+
- GIVEN a Terraform configuration for this resource
389
+
- WHEN the user declares a phase (for example `hot { ... }`)
390
+
- THEN the schema SHALL allow at most one such block for that phase and SHALL persist that phase as an object-shaped value in state, not as a single-element list
391
+
392
+
#### Scenario: Action block cardinality
393
+
394
+
- GIVEN a phase that supports an ILM action block
395
+
- WHEN the user declares that action (for example `forcemerge { ... }`)
396
+
- THEN the schema SHALL allow at most one such block and SHALL persist it as an object-shaped value in state, not as a single-element list
397
+
398
+
### Requirement: State schema version and upgrade (REQ-021)
399
+
400
+
The resource SHALL use a **non-zero**`schema.Schema.Version` for this resource type after this change.
401
+
402
+
The resource SHALL implement **`ResourceWithUpgradeState`** and SHALL migrate stored Terraform state from the **prior version** (list-shaped nested values for phases and ILM actions) to the **new version** (object-shaped nested values) for the same logical configuration.
403
+
404
+
The migration SHALL unwrap list-encoded values **only** for known ILM phase keys and known ILM action keys under those phases (including the delete-phase ILM action block named `delete`). The migration SHALL **not** alter the encoding of **`elasticsearch_connection`**.
405
+
406
+
#### Scenario: Upgrade from list-shaped phase state
407
+
408
+
- GIVEN persisted state where a phase is stored as a JSON array containing one object
409
+
- WHEN Terraform loads state and runs the state upgrader
410
+
- THEN the upgraded state SHALL store that phase as a single object (or equivalent null) consistent with `SingleNestedBlock` semantics
411
+
412
+
#### Scenario: Connection block unchanged by upgrade
413
+
414
+
- GIVEN persisted state that includes `elasticsearch_connection` as a list
415
+
- WHEN the state upgrader runs
416
+
- THEN the `elasticsearch_connection` value SHALL remain list-shaped as defined by the connection schema
417
+
418
+
### Requirement: Action fields optional with object-level AlsoRequires (REQ-022)
419
+
420
+
For the ILM action blocks **`forcemerge`**, **`searchable_snapshot`**, **`set_priority`**, **`wait_for_snapshot`**, and **`downsample`**, each attribute that is **required for API correctness when the action is declared** SHALL be **optional** at the Terraform attribute level (so an entirely omitted action block does not force those attributes to appear).
421
+
422
+
When the user **declares** one of these action blocks in configuration, validation SHALL require that all of the following previously required attributes are set (non-null), using object-level validation equivalent to **`objectvalidator.AlsoRequires`**:
423
+
424
+
-**`forcemerge`**: `max_num_segments`
425
+
-**`searchable_snapshot`**: `snapshot_repository`
426
+
-**`set_priority`**: `priority`
427
+
-**`wait_for_snapshot`**: `policy`
428
+
-**`downsample`**: `fixed_interval`
429
+
430
+
Existing attribute-level validators (for example minimum values) SHALL remain on those attributes where applicable.
431
+
432
+
#### Scenario: Omitted action block is valid
433
+
434
+
- GIVEN a phase without a particular action block (for example no `forcemerge` block)
435
+
- WHEN Terraform validates configuration
436
+
- THEN validation SHALL NOT fail solely because `max_num_segments` is unset
437
+
438
+
#### Scenario: Empty action block is invalid
439
+
440
+
- GIVEN the user declares `forcemerge { }` with no attributes
441
+
- WHEN Terraform validates configuration
442
+
- THEN validation SHALL fail with a diagnostic indicating the required fields when the block is present
443
+
444
+
#### Scenario: Searchable snapshot requires repository when present
445
+
446
+
- GIVEN the user declares `searchable_snapshot { force_merge_index = true }` without `snapshot_repository`
0 commit comments