Skip to content

Read configuration from env into typed options structs (koanf) - #381

Draft
fwiesel wants to merge 5 commits into
mainfrom
config/koanf
Draft

fwiesel wants to merge 5 commits into
mainfrom
config/koanf

Conversation

@fwiesel

@fwiesel fwiesel commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Read operator settings into module-owned options with
koanf. Each module supplies its defaults
through a constructor, including Shared. The command package contains no
module field-default literals or per-field registry.

The loader decodes one squashed aggregate. Generic hooks decode
comma-separated lists, JSON maps of the target type, and text-unmarshaler
types. Plain strings remain unchanged. Trait limits use an ordinary
map[string]int. The existing TraitConcurrency name remains as an alias,
without custom parsing or rendering methods.

Adding a supported field to an existing module needs no loader or flag
registration change in cmd. New defaults belong in that module's
constructor. Chart exposure and domain validation can require separate
changes. External overlays check Shared, certificate, and eviction fields,
including fresh mutable defaults, maps, lists, and text values.

The three commits keep these concerns separate:

  1. Read environment settings with module-owned defaults and generic decoding.
  2. Remove six --flag=$(ENV_VAR) chart arguments and document JSON maps.
  3. Generate optional flags once with sflags.

Description tags belong to the CLI commit. The chart commit remains separate
and reversible. Startup validation checks effective trait names and positive
limits before Kubernetes setup.

Native map forms and migration

Environment maps use JSON with double-quoted keys and integer values:

EVICTION_TRAIT_CONCURRENCY='{"CUSTOM_HANA_EXCLUSIVE_HOST":1,"CUSTOM_FOO":2}'

CLI map entries use repeated colon flags:

--eviction-trait-concurrency=CUSTOM_FOO:4
--eviction-trait-concurrency=CUSTOM_BAR:3

CLI entries merge keys into the environment map. A repeated key retains its
last CLI value. Unchanged environment keys remain. Empty environment text
clears the initial map. Empty CLI map input is invalid and does not clear it.

Old nonempty TRAIT=N environment values and custom CLI lists are unsupported.
They must migrate to JSON environment objects and repeated TRAIT:N CLI flags.
The former empty-CLI clear operation is no longer supported.

Existing repository tests and fixtures remain unchanged. No new tests are
committed. External native acceptance and reviewer probes check the actual
loader, aggregate flags, module ownership, validation, and chart encoding.

Relates to #13.

Layout reduction round (2026-11-01)

Controller-owned options now live in their controller files:

  • eviction options → internal/controller/eviction/controller.go
  • certificate options → internal/controller/node_certificate_controller.go
  • shared settings → internal/controller/hypervisor_controller.go (used by the manager and the Hypervisor controller only)

The separate internal/controller/eviction/options.go, internal/controller/options.go, and internal/config/options.go files no longer exist.

The env provider now uses the native key-only callback env.Provider("", ".", strings.ToLower).

Churn vs PR base (added + deleted lines): 537 → 471.

Future settings: add the field (tag + default) to the owning options struct in its controller file — no central registration. Separate new semantic field groups with a blank line to keep reformatting churn low.

Kubernetes uses the environment as its configuration interface.
Keep types, defaults, and domain validation in the owning modules so
new fields need no command registry or central field-default edits.
Decode the squashed aggregate once with generic map, list, and text
hooks. Plain strings and explicit empty values keep their meaning.

Use ordinary integer maps instead of a custom trait parser. Native
environment maps use JSON. Nonempty TRAIT=N lists are unsupported
and must migrate to JSON objects with double-quoted keys. Empty
environment text clears a map. Validate effective domain limits
before Kubernetes setup.

Keep optional CLI registration and descriptions in the later commit.

Signed-off-by: Fabian Wiesel <fabian.wiesel@sap.com>
The manager reads its settings from the environment, so remove the
--flag=$(ENV_VAR) container arguments. Document JSON trait maps so
chart users can migrate old TRAIT=N values to the native input form.

Signed-off-by: Fabian Wiesel <fabian.wiesel@sap.com>
Operators need optional command-line inspection and overrides.
Generate flags once from the aggregate so new supported fields in
existing modules need no registration changes in cmd. Let sflags
use native maps and lists rather than custom trait methods.

Repeated TRAIT:N flags merge map keys. The last value for a repeated
key wins, and unchanged environment keys remain. Old TRAIT=N CLI
lists are unsupported and must migrate to repeated colon entries.
Empty CLI map input is invalid, not a whole-map clear operation.
Use empty environment text when the map must start empty.

Keep descriptions here. Owning modules retain types and defaults.

Signed-off-by: Fabian Wiesel <fabian.wiesel@sap.com>
settings now live next to their owning controllers, so adding a setting touches one file per controller plus the chart

Signed-off-by: Fabian Wiesel <fabian.wiesel@sap.com>
the value callback added no transformation, so the native key-only form is sufficient

Signed-off-by: Fabian Wiesel <fabian.wiesel@sap.com>
@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown

Merging this branch will decrease overall coverage

Impacted Packages Coverage Δ 🤖
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller 73.26% (-1.51%) 👎
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/eviction 64.76% (-3.11%) 👎
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/global 0.00% (-100.00%) 💀 💀 💀 💀 💀
Coverage details

Compared to commit f5172c4 (run #41086905849)

Changed File Coverage Δ Total Covered Missed 🤖
github.com/cobaltcore-dev/openstack-hypervisor-operator/cmd/config.go 0.00% (ø) 0 0 0
github.com/cobaltcore-dev/openstack-hypervisor-operator/cmd/main.go 0.00% (ø) 0 0 0
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/eviction/controller.go 64.76% (-3.11%) 210 (+17) 136 (+5) 74 (+12) 👎
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/hypervisor_controller.go 72.73% (-7.27%) 132 (+12) 96 36 (+12) 👎
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/node_certificate_controller.go 70.83% (-10.12%) 48 (+6) 34 14 (+6) 💀
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/global/global.go 0.00% (-100.00%) 0 (-7) 0 (-7) 0 💀 💀 💀 💀 💀

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

Changed unit test files:

  • github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/eviction/controller_test.go
  • github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/hypervisor_controller_test.go
  • github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/global/global_test.go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant