netbox-community / netbox-community/netbox-chart
netbox-operator chart ships outdated CRDs, missing status.lastUpdated breaks operator change detection
- Dominant language
- Mustache
- Stars
- 357
- Forks
- 186
- Avg merge
- 1h 57m
- Merged PRs (30d)
- 52
Description
### Summary
The CRDs bundled in the netbox-operator chart are older than the operator image the chart deploys. The Prefix, IpAddress and IpRange CRDs are missing the status.lastUpdated property, which the operator has been writing since v0.2.51. The API server prunes the field, and because the operator reads it back for change detection, every reconcile is treated as out of date.
### Versions
Chart netbox-operator 1.2.145, appVersion 0.2.65 (also reproduced on main).
### What happens
On every reconcile the operator logs:
```
{"level":"info","msg":"unknown field \"status.lastUpdated\"","controller":"prefix","controllerGroup":"netbox.dev","controllerKind":"Prefix"}
```
The custom resources still reach Ready=True, so at first glance this looks like a cosmetic warning.
### Why it is not cosmetic
The operator writes the field in prefix_controller.go:
```go
if netboxPrefixModel.LastUpdated.IsSet() {
o.Status.LastUpdated = metav1.NewTime(*netboxPrefixModel.LastUpdated.Get())
}
```
and reads it back in pkg/netbox/api/change_detection.go:
```go
func IsUpToDate(...) bool {
if statusLastUpdated.IsZero() {
return false
}
...
}
```
Since the CRD has no such property, the value is pruned on write and always reads back as zero. IsUpToDate therefore always returns false, so the early return in pkg/netbox/api/prefix.go is never taken:
```go
if IsUpToDate(ctx, *prefixToUpdate.LastUpdated.Get(), prefixV1.Status.LastUpdated, prefixV1.Status.Conditions, prefixV1.Generation) {
return nil, true, nil
}
//update prefix since it does exist
resp, err = c.updatePrefix(ctx, prefixToUpdate.Id, prefix)
```
The result is an unnecessary write to NetBox on every reconcile even when nothing changed, one NetBox changelog entry per write, and a NetBox side last_updated bump that feeds back into the next comparison. The same pattern exists in ip_address.go and ip_range.go.
### Root cause
The chart ships its own copy of the CRDs, and that copy has not been refreshed since May 2025 (commit 83c8831a, "Update operator & CRDs to v0.1.0-alpha.7"), while the operator appVersion has kept moving. status.lastUpdated was introduced in operator v0.2.51.
Confirmed by comparing the chart CRDs against the operator repository:
```
netbox-chart 1.2.145 charts/netbox-operator/crds/prefixes.yaml status: conditions, id, url
netbox-operator v0.2.65 config/crd/bases/netbox.dev_prefixes.yaml status: conditions, id, url, lastUpdated
```
### Suggested fix
Refresh charts/netbox-operator/crds from the operator release that matches appVersion, and ideally have the appVersion bump automation copy config/crd/bases in the same change so the two cannot drift again.
### Workaround
Skip the chart CRDs and apply the CRDs from the matching operator release instead. Applying them without skipping the chart CRDs is not enough, since the next sync restores the older schema and the field is pruned again.
Contributor guide
No contributing guide indexed for this repository
Research direction
Compare the chart CRDs under charts/netbox-operator/crds, especially prefixes.yaml and the corresponding IpAddress and IpRange files, with config/crd/bases in the matching netbox-operator release. Start by checking the appVersion and the v0.2.51 schema change; done means all three CRDs expose status.lastUpdated and the chart copy stays aligned with the deployed operator version.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- helm, kubernetes
- Domain
- devops, infrastructure
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100