Skip to content

Improve configuration of operator #13

Open

Description

@fwiesel

Sparked by the following concern:

Can we move the netbox configuration to environment variables and don't initialize it within the main function but the controller?
Rationale is, although kubebuilder scaffolds some default options, it's a hassle to pass config via flags with kubernetes, especially secrets.

Activity

  1. fwiesel commented on Nov 21, 2024

    @fwiesel
    ContributorAuthor

    Most often used are:

    There are reasonable concerns with the viper.

    Alternatives I found:

    In my mind, exposing the configuration variables over the cli is essential for making them self-documenting (i.e cmd --help).
    I'd like to avoid reading config values from environment variables in "random places" in the code.

    Personally, I like "koanf".

  2. github-actions commented on Feb 20, 2025

    @github-actions

    This issue is stale because it has been open for 90 days with no activity.

  3. github-actions commented on Mar 6, 2025

    @github-actions

    This issue was closed because it has been inactive for 14 days since being marked as stale.

  4. reopened this on May 8, 2025
  5. github-actions commented on Aug 7, 2025

    @github-actions

    This issue is stale because it has been open for 90 days with no activity.

  6. github-actions commented on Aug 22, 2025

    @github-actions

    This issue was closed because it has been inactive for 14 days since being marked as stale.

  7. fwiesel commented on Oct 29, 2026

    @fwiesel
    ContributorAuthor

    Agent-generated research notes — 2026-10-29

    **AI-generated research notes ** The capabilities and licenses below are based on documentation and source review; integration testing and complete dependency-license verification are still needed.

    Configuration interface requirements

    The configuration interface should meet these requirements:

    • Each module/controller owns a typed options struct and receives the whole struct through its setup function.
    • Adding a supported field to an existing options group should automatically expose a CLI flag and an environment binding. No new per-field registration in main, handwritten BindFlags, or setup parameters.
    • Preserve a self-documenting CLI: --help should describe options, defaults, and environment bindings.
    • Parse configuration at the startup boundary, rather than reading environment variables in arbitrary controller code.
    • Prefer explicit configuration instances over package-level globals. This is a preference, not an absolute prohibition.
    • Go source is the source of truth. External/schema-first definitions are out. Generating bindings from Go declarations is still an option.
    • Accepted license families: Apache-2.0, MIT, BSD, ISC, and Creative Commons. Check the selected components and their dependencies; a top-level license alone is not blanket approval.

    A new module/group can require one-time inclusion and wiring. A new field within an existing group should not require more transport code. Using the new value in controller logic and testing it are separate from exposing it as configuration.

    Current ceremony

    charts/openstack-hypervisor-operator/values.yaml and templates/deployment.yaml currently transport several settings through environment variables that are expanded into CLI arguments (--option=$(ENV_VAR)). cmd/main.go then binds/parses individual settings and forwards them through setup parameters or globals.

    A generic Helm env map or flag map could remove the per-setting deployment-template mappings. Native env parsing would also remove the env-to-argument expansion layer while retaining CLI arguments for direct use and overrides. Secret references, OpenStack environment variables, and runtime settings such as GOMEMLIMIT need separate handling.

    Go-source-based approaches and libraries

    1. Automatic struct discovery, optionally using tags for metadata

    Library Own license Relevant capability
    go-flagsfiller MIT Generates a standard flag.FlagSet; optional native env bindings, automatic naming, defaults, and help.
    Kong MIT Nested struct-driven CLI/env parsing, defaults, help, and validation.
    Dials Apache-2.0 Typed, composable struct-driven sources, including env and standard/pflag flags. Defaults can be initialized Go values.
    Ardan Conf Apache-2.0 Integrated struct-driven CLI/env parsing and help; masking support for sensitive values.
    aconfig MIT Struct-driven defaults/files/env/flags; exposes its standard FlagSet for additional flags.
    boa MIT Automatic field discovery on Cobra; metadata through tags or programmatic Go APIs.
    sflags BSD-3-Clause Struct-to-flag adapters for multiple parsers; env capabilities depend on the adapter.

    Additional struct-driven candidates: go-arg (BSD-2-Clause), go-flags (BSD-3-Clause), mcli (MIT), and structcli (MIT). structcli brings Cobra and Viper, which matters when comparing smaller/composable alternatives.

    Tags are not required for basic field discovery. A bare Go field supplies its name and type, however, not its semantic description or non-zero default; that metadata must live somewhere.

    2. Field comments → generated bindings

    No maintained turnkey library was found in this research that generates CLI bindings, env bindings, and help from Go field comments alone. This is a possible design, not an identified drop-in solution.

    Building blocks:

    • envdoc — MIT; extracts field comments and generates environment documentation, not parsing/bindings.
    • Jennifer — MIT; emits Go code, not configuration-field discovery.
    • Go's go/ast, go/parser, go/doc, and go/types — BSD-3-Clause; read authoritative source declarations and comments.

    This path would require maintaining a generator. Generated bindings would be output, not a second source of truth.

    3. Self-describing field types

    Mostly extension mechanisms in existing registrars:

    • Kong supports custom text decoding/mappers and type-level validation.
    • Dials supports custom text decoding and typed enums whose allowed values appear in flag help.
    • go-flagsfiller supports custom text-unmarshal types and extensible conversion.

    These can move parsing and validation into Go types. They do not universally discover type-owned defaults, per-setting descriptions, and env policy. A complete self-describing-type design would still need glue. Adding a field of an existing supported type can be automatic; inventing a new option type may need additional code.

    4. Typed descriptors/programmatic metadata

    • Enflag — MIT; generic bindings combining env, CLI, defaults, and help.
    • boa's programmatic API — MIT; discovers plain fields and attaches metadata through typed API calls.
    • urfave/cli v3 — MIT; declarative Go flag objects with destinations, env sources, defaults, and help.

    Boa still discovers fields automatically; its API calls supply metadata. Enflag and urfave/cli require a declaration/binding per option. That can live in the owning module rather than main, but is a weaker fit for strict “add only a field.”

    Composable source-loading alternatives

    Koanf has an MIT-licensed core; its reviewed core dependencies are also MIT. Providers are separately selectable. It handles source loading/merging and unmarshalling, but does not itself generate CLI flags/help from fields; pair it with a struct-to-flag adapter.

    Similarly, ff (Apache-2.0) handles flags-first source precedence, not struct discovery. It can use an adapter-generated FlagSet. Both deliberately support composition rather than requiring a larger integrated framework.

    Relevant evolution: ff/v3 ignores empty env values, while the available v4.0.0-beta.1 uses LookupEnv and has an upstream test for an explicitly empty env value overriding a non-empty default. V4 remains a prerelease.

    Compatibility checks before choosing

    Candidate implementations should be checked for the following behaviour:

    • Every intended options field is registered, or explicitly excluded; unsupported types must not silently lose a setting.
    • Existing CLI names and Boolean syntax remain usable, especially --leader-elect and --metrics-secure=false.
    • Explicit empty regex values survive transport and parsing. An empty include regex means “include all interfaces,” not “use the default regex.”
    • CLI/env/default precedence is deliberate, including collection replacement versus appending.
    • Preserve comma-separated namespaces, deduplication, TRAIT=N overrides, and migration-limit validation.
    • --help and --version work without required runtime configuration. Handling invalid lower-priority env values needs explicit tests.
    • Preserve ctrlzap.Options.BindFlags, which uses a standard flag.FlagSet, without manual per-application-option wiring in main.
    • Controllers/tests can receive independent options instances without saving/restoring global configuration.

    Specific caveats from source review: go-flagsfiller's native env parsing occurs during flag registration, so invalid env can prevent help or a later CLI override; its reviewed implementation does not directly bind map[string]int. aconfig has old/new parser modes whose CLI compatibility needs checking.

    These are candidate designs rather than an implementation recommendation. They should be evaluated against the configuration-interface requirements, compatibility checks, and license policy before selecting an implementation.

  8. reopened this on Nov 2, 2026
  9. added
    enhancementNew feature or request
    and removed on Nov 2, 2026
  10. fwiesel commented on Nov 2, 2026

    @fwiesel
    ContributorAuthor

    Four comparison PRs implement this with different configuration libraries. Each follows the same rule: a setting is declared in the options struct of its owning controller, with no central per-variable registration in cmd.

    Diff stats are the complete PR diff against each PR's own base (merge base with main). Churn is added + deleted lines.

    PR Approach Files Added Deleted Churn Head
    #373 go-flagsfiller (struct tags) 11 173 172 345 6921cfc
    #382 envconfig + sflags 11 204 173 377 2f83233
    #379 cobra + viper 11 264 172 436 dcfd50a
    #381 koanf 12 298 173 471 6286311

    Notes:

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions