Skip to content

refactor: validated config types and pipeline controller architecture#794

Closed
adwk67 wants to merge 14 commits into
mainfrom
feature/validated-config-types-2
Closed

refactor: validated config types and pipeline controller architecture#794
adwk67 wants to merge 14 commits into
mainfrom
feature/validated-config-types-2

Conversation

@adwk67
Copy link
Copy Markdown
Member

@adwk67 adwk67 commented May 12, 2026

Note

These PRs are primarily for validating the refactoring process and can be ignored, merged, closed etc. as we see fit.

Summary

  • Adds a framework module with validated string types (ClusterName, RoleName, RoleGroupName, etc.), type-safe label builders, PDB/StatefulSet builders, and product logging utilities — designed for eventual migration to operator-rs
  • Replaces the monolithic 1511-line airflow_controller.rs with a 5-stage pipeline architecture: dereference → validate → build → apply → update_status, where the build stage is infallible
  • Introduces ValidatedAirflowCluster as a central validated type holding all data needed by the build stage, with compile-time length assertions via attributed_string_type! macro
  • Removes dead code from operations/, service.rs, and crd/mod.rs
  • Shortens test role group names to fit the 16-character RoleGroupName limit

Commit structure

Each commit is designed to be reviewed in isolation:

  1. chore: add regex and uuid dependencies — dependency additions only
  2. feat: add framework macrosattributed_string_type! macro
  3. feat: add framework validated typesClusterName, RoleName, etc.
  4. feat: add framework KVP module — type-safe label builders
  5. feat: add framework builders — PDB, StatefulSet, meta, pod builders
  6. feat: add framework utilities — role utils, logging, controller utils
  7. refactor: derive Ord/PartialOrd on AirflowRole — prep for BTreeMap keys
  8. refactor: make stateful_set_service_name generic — decouple from AirflowCluster
  9. refactor: simplify build_airflow_template_envs signature — reduce parameter count
  10. refactor: replace monolithic controller with pipeline architecture — the big transformation
  11. refactor: remove dead code — clean up operations/, service.rs, crd
  12. refactor: extract controller into submodules — split into dereference/validate/build/apply/update_status
  13. refactor: shorten test role group names — fit 16-char RoleGroupName limit
  14. chore: remove REVIEW comments — clean up review markers

Test plan

  • All 92 unit tests pass at every commit (cargo test)
  • Only 1 pre-existing warning throughout (unused GIT_CREDENTIALS_SECRET_PROPERTY)
  • Kuttl integration tests (logging, resources) — role group name changes are reflected in test templates
  • Verify generated CRD is unchanged

🤖 Generated with Claude Code

adwk67 and others added 14 commits May 12, 2026 10:15
These dependencies are required by the framework module that will be
added in subsequent commits:

- regex: used by the attributed_string_type! macro for compile-time
  validated string types (e.g. RFC 1035/1123 name validation)
- uuid: used for generating unique owner references in cluster
  resource management

No code changes — dependencies are not yet referenced.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add the attributed_string_type! macro which generates strongly-typed
wrappers around strings with compile-time validation attributes:
- RFC 1035 label names, RFC 1123 label/subdomain names
- Label value constraints, length limits, regex patterns
- Automatic FromStr, Display, Serialize/Deserialize, JsonSchema impls
- Compile-time constant checks (IS_RFC_1035_LABEL_NAME, MAX_LENGTH, etc.)

Also adds a small constant! helper macro for validated const values.

The NameIsValidLabelValue trait is included in framework.rs as the
macro references it for label-value-safe types.

These macros are the foundation for the validated type system that
replaces stringly-typed names throughout the operator.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduce strongly-typed wrappers for Kubernetes and operator names:

- types/common: Port type with range validation
- types/kubernetes: ConfigMapName, ServiceName, StatefulSetName,
  ListenerName, NamespaceName, Uid — each with appropriate RFC
  constraints and max_length limits
- types/operator: ProductName, ClusterName, RoleName, RoleGroupName,
  ControllerName, OperatorName — with operator-specific length
  budgets ensuring the combined <cluster>-<role>-<rolegroup> fits
  within StatefulSet name limits (52 chars)

Operator-specific values (max_length, examples) are flagged with
REVIEW comments for parameterisation when this module moves to
operator-rs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add label construction functions that accept validated types
(ProductName, OperatorName, ClusterName, etc.) instead of raw
strings, eliminating the possibility of label value constraint
violations at the call site.

Provides: recommended_labels, role_group_selector_labels,
prometheus_labels, and prometheus_annotations.

The HasName trait is added to framework.rs as it is required by the
label functions to extract names from cluster objects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add type-safe builder functions for constructing Kubernetes resources
using validated types instead of raw strings:

- builder/meta: ObjectMeta with validated names, labels, owner refs
- builder/pdb: PodDisruptionBudget with role-aware max_unavailable
- builder/pod/container: container construction with ports, env vars,
  volume mounts, resource limits, probes
- builder/pod/volume: config map and empty dir volume helpers
- builder/statefulset: StatefulSet with pod template, service name,
  replicas, restart policy

The HasUid trait is added to framework.rs as it is required by the
meta builder for constructing owner references.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Complete the framework module with:

- role_utils: role config validation, merging, and iteration with
  validated types — replaces stringly-typed role/rolegroup handling
- role_group_utils: QualifiedRoleGroupName with compile-time length
  assertions ensuring <cluster>-<role>-<rolegroup> fits within
  StatefulSet, Service, ConfigMap, and Listener name limits
- controller_utils: config merging for role/rolegroup hierarchies,
  producing validated config per rolegroup
- cluster_resources: typed wrapper around operator-rs ClusterResources
- product_logging: validated logging config types
  (ValidatedContainerLogConfigChoice, VectorContainerLogConfig)

Modules marked #[allow(dead_code)] are not yet referenced by the
controller — they will be wired in when the controller pipeline is
replaced in a later commit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Required so AirflowRole can be used as a BTreeMap key in the new
controller's validated cluster type. No behavioural change — the
enum already derives Eq/Hash, and the variant ordering is stable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The function only calls rolegroup_ref.object_name() which is
available on any RoleGroupRef<T: Resource>. Making it generic
allows the new controller to call it with
RoleGroupRef<ValidatedAirflowCluster>.

No behavioural change — existing callers continue to work.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the &ExecutorConfig parameter with a plain bool
(vector_agent_enabled) — the function only ever read
config.logging.enable_vector_agent from it.

This decouples the function from the ExecutorConfig type, allowing
the new controller to call it with a pre-validated bool without
needing to reconstruct an ExecutorConfig.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the monolithic reconcile_airflow with a five-stage pipeline:
dereference → validate → build → apply → update_status.

The build stage is infallible — all validation and fallible operations
(config generation, PodBuilder/ContainerBuilder usage, logging
validation) happen in the validate stage. Services and PDBs are now
built inline rather than delegating to service.rs and operations/.

Also updates product_logging.rs and controller_commons.rs to accept
pre-validated types (ValidatedContainerLogConfigChoice) instead of
raw Logging<C>/ContainerLogConfig, making those functions infallible.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Delete the operations/ module (graceful_shutdown, pdb) — its
functionality is now handled inline by the validate and build stages.

Remove dead functions from service.rs (service building is now inline
in the controller build stage) and crd/mod.rs (build_recommended_labels
replaced by framework::kvp::label functions).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split the monolithic airflow_controller.rs into controller/ with
submodules: dereference, validate, build (+ build/role_group_builder),
apply, and update_status.

This is a purely structural refactor — no logic changes. Each pipeline
stage now lives in its own file for easier navigation and review.

Rename airflow_controller module to controller in main.rs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
RoleGroupName has a max_length of 16 characters. Rename test role
groups to fit within this limit:

- resources-from-role (19) → from-role (9)
- resources-from-role-group (25) → from-rg (7)
- resources-from-pod-overrides (28) → from-overrides (14)
- automatic-log-config (20) → auto-log-cfg (12)
- custom-log-config (17) → custom-log-cfg (14)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove all // REVIEW: comments that were added to aid code review.
These served their purpose during the review process and are no
longer needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@adwk67
Copy link
Copy Markdown
Member Author

adwk67 commented May 12, 2026

Closing in favour of #795

@adwk67 adwk67 closed this May 12, 2026
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