Skip to content

Feat/field manager#694

Open
gustavodiaz7722 wants to merge 2 commits intoaws-controllers-k8s:mainfrom
gustavodiaz7722:feat/field-manager
Open

Feat/field manager#694
gustavodiaz7722 wants to merge 2 commits intoaws-controllers-k8s:mainfrom
gustavodiaz7722:feat/field-manager

Conversation

@gustavodiaz7722
Copy link
Copy Markdown
Member

feat: Add field manager for managing fields with separate API operations

Summary

Introduces the field manager pattern to the ACK code generator. This allows a parent resource to declare fields whose lifecycle (create, update, delete, read) is managed by separate AWS API operations, without exposing those fields as standalone Kubernetes CRDs.

For example, a BackupVault resource can declare AccessPolicy, Notifications, and LockConfiguration as managed fields. Each gets its own generated manager package that handles CRUD via dedicated API operations (PutBackupVaultAccessPolicy, DeleteBackupVaultAccessPolicy, etc.), while the user interacts with a single BackupVault CR.

generator.yaml interface

Managed fields are defined inline on individual fields using the manager key:

resources:
  BackupVault:
    fields:
      AccessPolicy:
        manager:
          hooks:
            sdk_read_one_post_request:
              template_path: hooks/backup_vault_access_policy/sdk_read_one_post_request.go.tpl
      LockConfiguration:
        manager:
          fields:
            ChangeableForDays:
              compare:
                is_ignored: true
          find_operation:
            custom_method_name: customFindLockConfiguration

The manager block accepts the same configuration as a top-level resource (hooks, renames, exceptions, fields, find_operation, etc.), scoped to the managed field's own operations.

What the code generator produces

For each managed field, the code generator creates a package under pkg/resource/<parent>/<field>/:

File Purpose
manager.go Manager struct, NewManager(), Sync(), Get(), delta computation, singleton logic
sdk.go sdkFind(), sdkCreate(), sdkDelete(), request payload builders
delta.go Field-by-field comparison respecting compare.is_ignored

On the parent side, generated code is injected into:

  • sdkCreate — marks resource unsynced if managed field spec is non-nil (forces reconcile loop)
  • sdkFind — calls Get() on each field manager to populate parent spec
  • sdkUpdate — calls Sync() when delta.DifferentAt("Spec.<Field>"), short-circuits if only managed fields changed
  • sdkDelete — syncs each managed field with nil desired state before deleting parent

Auto-inference

Operations

The code generator automatically infers API operation bindings from the SDK model using naming conventions. For parent Foo and managed field Bar, it tries suffixes in preference order:

  1. {Verb}{Parent}{Field} — e.g. PutBackupVaultLockConfiguration
  2. {Verb}{Field} — e.g. PutNotifications
  3. {Verb}{Parent}{Singular} — e.g. TagBackupVault
  4. {Verb}{Singular} — e.g. TagResource
  5. {Verb}Resource — generic fallback

With verb prefixes per operation type:

  • Create: Put, Create, Set, Tag
  • Delete: Delete, Remove, Untag
  • Get: Get, Describe, List

Explicit operations: entries in generator.yaml always take precedence.

Primary keys

The parent's primary key is automatically propagated to each managed field. The original SDK field name is resolved by reverse-looking up the parent's renames (e.g. parent renames BackupVaultNameName, so the managed field gets BackupVaultName as its primary key). The injected field config carries is_primary_key: true, go_tag: json:"-", and compare.is_ignored: true.

Config layer changes

  • New FieldManagerConfig type (embeds ResourceConfig)
  • New Manager *FieldManagerConfig field on FieldConfig (YAML key: manager)
  • NormalizeManagedFields() promotes field-level manager configs into the internal ManagedFields map
  • InferManagedFieldOperations() auto-discovers SDK operations
  • InferManagedFieldPrimaryKeys() auto-derives primary keys from parent
  • Accessor methods: GetManagedFields(), IsManagedField(), GetFieldManagerConfig(), GetParentResourceName()

Template files added

  • field_manager.go.tpl — main manager scaffold
  • field_manager_singleton.go.tpl — singleton pattern (key, sync, Get, convertFromParent)
  • sdk_create_field_manager_requeue.go.tpl — requeue on create
  • sdk_update_field_manager_sync.go.tpl — sync on update
  • sdk_delete_field_manager_sync.go.tpl — cleanup on delete
  • sdk_find_field_manager_get.go.tpl — populate on find

Testing

  • Table-driven unit tests for inferManagedFieldOps covering 12 scenarios: standard patterns, prefix preference, singular forms, generic Resource suffix, explicit binding preservation, partial matches, and no-match cases
  • Validated against the backup-controller with three managed fields (AccessPolicy, Notifications, LockConfiguration) — all produce identical generated code and compile cleanly

@ack-prow ack-prow Bot requested review from a-hilaly and jlbutler May 1, 2026 18:09
@ack-prow
Copy link
Copy Markdown

ack-prow Bot commented May 1, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: gustavodiaz7722
Once this PR has been reviewed and has the lgtm label, please assign jlbutler for approval by writing /assign @jlbutler in a comment. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ack-prow
Copy link
Copy Markdown

ack-prow Bot commented May 1, 2026

@gustavodiaz7722: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
verify-attribution 1332fa4 link false /test verify-attribution
unit-test 1332fa4 link true /test unit-test
lambda-controller-test 1332fa4 link true /test lambda-controller-test
s3-olm-test 1332fa4 link false /test s3-olm-test
cloudfront-controller-test 1332fa4 link true /test cloudfront-controller-test
documentdb-controller-test 1332fa4 link true /test documentdb-controller-test
ecr-controller-test 1332fa4 link true /test ecr-controller-test
eventbridge-controller-test 1332fa4 link true /test eventbridge-controller-test
pipes-controller-test 1332fa4 link true /test pipes-controller-test
eks-controller-test 1332fa4 link true /test eks-controller-test
apigatewayv2-controller-test 1332fa4 link true /test apigatewayv2-controller-test
acm-controller-test 1332fa4 link true /test acm-controller-test
ec2-controller-test 1332fa4 link true /test ec2-controller-test
iam-controller-test 1332fa4 link true /test iam-controller-test
dynamodb-controller-test 1332fa4 link true /test dynamodb-controller-test
efs-controller-test 1332fa4 link true /test efs-controller-test
prometheusservice-controller-test 1332fa4 link true /test prometheusservice-controller-test
s3-controller-test 1332fa4 link true /test s3-controller-test

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

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