resource_remote: add mirror_strategy attribute (fixes missing API field) #19

Merged
benvin merged 2 commits from benvin/mirror-strategy into main 2026-08-13 19:56:58 +10:00
Member

Why

The provider exposed mirrorlist but not mirror_strategy, so the API's mirror load-balancing strategy could not be set from Terraform — least_conn was unreachable and remotes were stuck on the round_robin default.

How

  • schema: optional mirror_strategy string on the remote resource (values round_robin/least_conn; only valid on rpm/deb/apk remotes).
  • ValidateConfig: reuses the existing rpm/deb/alpine gate to reject mirror_strategy on other remote types at plan time, and validates the enum value (API 400 is the backstop).
  • wire model + modelToAPI/apiToModel: sends mirror_strategy only when set; empty→null on read to avoid a perpetual diff.
  • models.go: mirror_strategy,omitempty wire field.
  • datasource (computed) + README + rpm example.
  • tests: modelToAPI/apiToModel round-trip (incl. null→omitted) and the ValidateConfig matrix (accepted on rpm/deb/alpine, rejected elsewhere, invalid enum rejected, null anywhere ok).

Scoped to rpm/deb/alpine exactly like mirrorlist; no unrelated attributes touched. go build/go test/go vet/gofmt and pre-commit run --all-files all green.

## Why The provider exposed `mirrorlist` but not `mirror_strategy`, so the API's mirror load-balancing strategy could not be set from Terraform — `least_conn` was unreachable and remotes were stuck on the `round_robin` default. ## How - **schema**: optional `mirror_strategy` string on the remote resource (values `round_robin`/`least_conn`; only valid on rpm/deb/apk remotes). - **ValidateConfig**: reuses the existing rpm/deb/alpine gate to reject `mirror_strategy` on other remote types at plan time, and validates the enum value (API 400 is the backstop). - **wire model + modelToAPI/apiToModel**: sends `mirror_strategy` only when set; empty→null on read to avoid a perpetual diff. - **models.go**: `mirror_strategy,omitempty` wire field. - **datasource** (computed) + **README** + rpm example. - **tests**: modelToAPI/apiToModel round-trip (incl. null→omitted) and the ValidateConfig matrix (accepted on rpm/deb/alpine, rejected elsewhere, invalid enum rejected, null anywhere ok). Scoped to rpm/deb/alpine exactly like `mirrorlist`; no unrelated attributes touched. `go build`/`go test`/`go vet`/`gofmt` and `pre-commit run --all-files` all green.
unkin-agent added 1 commit 2026-08-13 17:51:30 +10:00
resource_remote: add mirror_strategy attribute
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
c69c3d9f74
The provider exposed mirrorlist but not mirror_strategy, so the API's
mirror load-balancing strategy (round_robin/least_conn) was unreachable
via Terraform. Add mirror_strategy the same way mirrorlist was added,
scoped to rpm/deb/alpine remotes.

- schema: optional string mirror_strategy on the remote resource
- ValidateConfig: reject on non-rpm/deb/alpine types and validate the
  round_robin/least_conn enum at plan time
- wire model + modelToAPI/apiToModel (empty->null to avoid perpetual diff)
- datasource (computed) + README + rpm example
- unit tests: modelToAPI/apiToModel round-trip and ValidateConfig matrix
unkin-agent added 1 commit 2026-08-13 19:27:51 +10:00
resource_remote: make mirror_strategy Computed to avoid plan churn
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
24c11d233a
The API stores mirror_strategy NOT NULL DEFAULT 'round_robin' and always
returns it on GET, so an Optional-only attribute (mapping empty->null on
read) put 'round_robin' into state while config was null, showing a
perpetual 'round_robin -> null' diff for every remote that did not set it.

- schema: mirror_strategy is now Optional+Computed with a round_robin
  default, mirroring how the description attribute handles an
  API-defaulted scalar; state can hold the API's round_robin with no diff
- apiToModel: pass the API value straight through, settling an empty
  create-response to the round_robin default (no more empty->null)
- datasource: read the value through directly (drop the shared helper)
- tests: assert the GET-returns-round_robin refresh path yields no
  post-apply diff, the empty create-response settles to the default, and
  the schema attribute is Optional+Computed

Removed the now-unused stringOrNull helper.
Author
Member

Addressed the plan-churn review finding in 24c11d2.

The API stores mirror_strategy NOT NULL DEFAULT 'round_robin' and always returns it on GET, so the original Optional-only attribute (empty→null on read) wrote round_robin to state while config was null — a perpetual round_robin -> null diff for every remote that didn't set it.

Fix (mirrors how description handles an API-defaulted scalar):

  • mirror_strategy is now Optional+Computed with a round_robin default, so state can hold the API's value with no diff.
  • apiToModel passes the API value straight through and settles an empty create-response to the round_robin default (no more empty→null).
  • Datasource reads the value directly; removed the now-unused stringOrNull helper.
  • Added a regression test asserting the GET-returns-round_robin refresh path yields no post-apply diff, plus create-response-settles-to-default and schema-is-Optional+Computed checks.

go build/test/vet/gofmt and pre-commit run --all-files all green.

Addressed the plan-churn review finding in 24c11d2. The API stores `mirror_strategy` NOT NULL DEFAULT 'round_robin' and always returns it on GET, so the original Optional-only attribute (empty→null on read) wrote `round_robin` to state while config was null — a perpetual `round_robin -> null` diff for every remote that didn't set it. Fix (mirrors how `description` handles an API-defaulted scalar): - `mirror_strategy` is now Optional+Computed with a `round_robin` default, so state can hold the API's value with no diff. - `apiToModel` passes the API value straight through and settles an empty create-response to the `round_robin` default (no more empty→null). - Datasource reads the value directly; removed the now-unused `stringOrNull` helper. - Added a regression test asserting the GET-returns-round_robin refresh path yields no post-apply diff, plus create-response-settles-to-default and schema-is-Optional+Computed checks. `go build/test/vet/gofmt` and `pre-commit run --all-files` all green.
benvin merged commit f947f23e45 into main 2026-08-13 19:56:58 +10:00
benvin deleted branch benvin/mirror-strategy 2026-08-13 19:56:59 +10:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unkin/terraform-provider-artifactapi#19