Tagger initializer issues a no-op spec Update on every reconcile
- Dominant language
- Go
- Stars
- 481
- Forks
- 131
- Avg merge
- 2d 1h
- Merged PRs (30d)
- 11
Description
### What happened?
The `Tagger` initializer ends with an unconditional `kube.Update`. The managed
reconciler calls `Initialize` on every pass, and after the first reconcile the
external tags are already in `spec.forProvider.tags`, so from then on we issue a
full spec update per taggable managed resource per poll interval that changes
nothing.
The API server byte-compares the object and discards the identical update before
it reaches etcd, so this is not an etcd write problem. It is an API call that
shows up as an audit event with a request body, at a higher audit level than a
read. On a cluster with a few thousand managed resources and audit logs shipped
somewhere that bills for ingest, that is a continuous and pointless cost.
I also see this on every resource creation:
```
2025-03-06T09:21:58+01:00 DEBUG provider-aws Cannot initialize managed resource {"controller": "managed/ec2.aws.upbound.io/v1beta1, kind=securitygroup",
"request": {"name":"example4"},
"uid": "6110a508-2be7-470c-8d00-10302dc9c270",
"version": "101685",
"external-name": "",
"error": "Operation cannot be fulfilled on securitygroups.ec2.aws.upbound.io \"example4\": the object has been modified; please apply your changes to the latest version and try again"}
```
Dropping the update when nothing changed removes both.
#222 lists "move adding the default tags to the Create step, so we don't
initialize them every reconciler run" as one option, but that issue is about tags
in `spec.forProvider` making them impossible to ignore with management policies,
which is a separate concern.
### How can we reproduce it?
Used `crossplane/upjet-provider-template` (hashicorp/null provider, no cloud
credentials needed).
1. Added a custom Tagger initializer using the `"triggers"` field in both config files:
```go
r.InitializerFns = append(r.InitializerFns, func(c client.Client) managed.Initializer {
return ujconfig.NewTagger(c, "triggers")
})
```
2. Set `r.UseAsync = true`, for async status updates and realistic concurrency.
3. Added `time.Sleep(500 * time.Millisecond)` in `TerraformSetupBuilder`, to
simulate slow provider setup.
4. Regenerated controllers and deployed with `make local-deploy`.
Create one MR and watch `metadata.resourceVersion` stay put while the audit log
gets an `update` entry for it every poll interval.
Contributor guide
Research direction
Start at the Tagger initializer returned by NewTagger and trace its unconditional kube.Update call. Reproduce with crossplane/upjet-provider-template using hashicorp/null, the triggers initializer, and the async setup described here; done means unchanged reconciles stop producing update audit entries while tag changes still update the resource.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, kubernetes
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100