Skip to content

Add Configured condition to all controllers - #426

Draft
adamtrizuljak-sap wants to merge 5 commits into
mainfrom
feat/configured-condition
Draft

Add Configured condition to all controllers#426
adamtrizuljak-sap wants to merge 5 commits into
mainfrom
feat/configured-condition

Conversation

@adamtrizuljak-sap

@adamtrizuljak-sap adamtrizuljak-sap commented Jun 30, 2026

Copy link
Copy Markdown

Previously, some controllers did not set the Configured condition after performing the configuration. They only set the Ready condition, which was ambiguous. This PR explicitly sets the Configured condition based on the provider success and ensures that the Ready condition is set correctly at the end of the reconcile loop.

  • Initialize the ConfiguredCondition
  • Add deferred call of conditions.RecomputeReady() to ensure the Ready condition is evaluated and set at the end of the reconcile loop
  • cond := conditions.FromError(err) already returns the Configured condition, so we just remove the next line that was overriding it with the Ready condition
  • Update the associated tests to check that the Configured condition has been set
  • Add Kubebuilder printcolumn for the Configured condition

Todo

  • In BGP controller, EVPNInstance (and other) controllers check if it's correct to just replace the ReadyCondition to ConfiguredCondition - I suspect both conditions should be set
  • Fix tests
  • Squash commits

Comment thread internal/controller/core/bgp_controller.go

@felix-kaestner felix-kaestner left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we are adding a new condition to these resources, should we also add a printcolumn like so?

diff --git a/api/core/v1alpha1/acl_types.go b/api/core/v1alpha1/acl_types.go
index 6501f362..a7a01b70 100644
--- a/api/core/v1alpha1/acl_types.go
+++ b/api/core/v1alpha1/acl_types.go
@@ -122,6 +122,7 @@ type AccessControlListStatus struct {
 // +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name`
 // +kubebuilder:printcolumn:name="Entries",type=string,JSONPath=`.status.entriesSummary`,priority=1
 // +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status`
+// +kubebuilder:printcolumn:name="Configured",type=string,JSONPath=`.status.conditions[?(@.type=="Configured")].status`,priority=1
 // +kubebuilder:printcolumn:name="Paused",type=string,JSONPath=`.status.conditions[?(@.type=="Paused")].status`,priority=1
 // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"

@adamtrizuljak-sap
adamtrizuljak-sap force-pushed the feat/configured-condition branch 2 times, most recently from 032b437 to 8d76d7d Compare July 6, 2026 12:47
@github-actions github-actions Bot added size/M and removed size/L labels Jul 6, 2026
@adamtrizuljak-sap
adamtrizuljak-sap marked this pull request as ready for review July 6, 2026 13:35
@adamtrizuljak-sap
adamtrizuljak-sap requested a review from a team July 6, 2026 13:35
Comment thread internal/controller/core/dhcprelay_controller.go
@nikatza

nikatza commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

@adamtrizuljak-sap We merged the aaa resource in the mean time, which unfortunately has the same issue that you fix in this PR. Could you please update your PR and include a fix for it?

Likewise, in this PR we only tackle core resources. There are some other resources like bordergateway and system in cisco/nx that could use this fix too.

Thanks a lot for your contribution! 🔥

@adamtrizuljak-sap

Copy link
Copy Markdown
Author

@adamtrizuljak-sap We merged the aaa resource in the mean time, which unfortunately has the same issue that you fix in this PR. Could you please update your PR and include a fix for it?

Likewise, in this PR we only tackle core resources. There are some other resources like bordergateway and system in cisco/nx that could use this fix too.

Thanks a lot for your contribution! 🔥

Done. Are there any other resources that need this change?

@felix-kaestner felix-kaestner left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We currently have some places in the codebase that use the check for IsReady on resources, that previously only had the Ready condition, e.g.

if !conditions.IsReady(vrf) {
// VRF uses ReadyCondition as its top-level configured state (no separate ConfiguredCondition).

This is combined with a watch trigger to do reconcilation once this condition changes, e.g.

return conditions.IsReady(oldVRF) != conditions.IsReady(newVRF)

Now that resources like the VRF get a configured condition, I think those checks should also be adjusted to use the IsConfigured check instead of the IsReady check,

// IsConfigured looks at the [v1alpha1.ConfiguredCondition] condition type and returns true
// if that condition is set to true and the observed generation matches the object's generation.
func IsConfigured(target Getter) bool {
condition := Get(target, v1alpha1.ConfiguredCondition)
if condition == nil {
return false
}
if m, ok := target.(metav1.Object); ok && condition.ObservedGeneration != m.GetGeneration() {
return false
}
return condition.Status == metav1.ConditionTrue
}

So I think one additional task would be to go through the codebase and find usages of IsReady which were used for resources that only had the Ready condition previously and change those to now check for IsConfigured instead.

@adamtrizuljak-sap
adamtrizuljak-sap force-pushed the feat/configured-condition branch from 1b654c2 to 4ead8e3 Compare July 9, 2026 11:29
@adamtrizuljak-sap

adamtrizuljak-sap commented Jul 9, 2026

Copy link
Copy Markdown
Author

We currently have some places in the codebase that use the check for IsReady on resources, that previously only had the Ready condition, e.g.

if !conditions.IsReady(vrf) {
// VRF uses ReadyCondition as its top-level configured state (no separate ConfiguredCondition).

...

@felix-kaestner I think that this should not be an issue or a change in behavior? At the end of reconciliation, RecomputeReady() loops over all conditions of the resource and if any of the conditions is False, it sets the Ready condition to False

https://github.com/ironcore-dev/network-operator/blob/main/internal/conditions/conditions.go#L119

Therefore if the Configured condition is False, the Ready condition will also be False and the following check should still have the same behavior. Plus it will trigger the reconciliation if any other condition becomes False, not just the Configured condition

This is combined with a watch trigger to do reconcilation once this condition changes, e.g.

return conditions.IsReady(oldVRF) != conditions.IsReady(newVRF)

Do you think that we should also explicitly evaluate the Configured condition?

@felix-kaestner

Copy link
Copy Markdown
Contributor

Do you think that we should also explicitly evaluate the Configured condition?

Yes, I think that would be more semantically correct here, as the intention is "I can't configure X before configuring Y". The reason this currently uses the "Ready" condition was simply that these resources didn't have a "Configured" condition, as is also commented in those places. Now that we introduce the "Configured" condition I think we should change that.

@adamtrizuljak-sap
adamtrizuljak-sap force-pushed the feat/configured-condition branch from 4ead8e3 to d5f5438 Compare July 13, 2026 14:53
@adamtrizuljak-sap

Copy link
Copy Markdown
Author

Do you think that we should also explicitly evaluate the Configured condition?

Yes, I think that would be more semantically correct here, as the intention is "I can't configure X before configuring Y". The reason this currently uses the "Ready" condition was simply that these resources didn't have a "Configured" condition, as is also commented in those places. Now that we introduce the "Configured" condition I think we should change that.

Got it. @nikatza helped me understand the problem - you were talking about only about the controllers that depend on other referenced resources.

For example the BGPPeer controller watches referenced BGP and VRF resources and triggers a self-reconciliation when their conditions change. Since these resources now expose a proper Configured condition, we update the checking logic to use it instead of the Ready condition (which now has too broad meaning).

@adamtrizuljak-sap
adamtrizuljak-sap force-pushed the feat/configured-condition branch from d5f5438 to 691ea9a Compare July 14, 2026 09:12
@swagner-de
swagner-de marked this pull request as draft July 23, 2026 12:47
@adamtrizuljak-sap
adamtrizuljak-sap force-pushed the feat/configured-condition branch from 691ea9a to 2434e13 Compare July 24, 2026 09:54
@adamtrizuljak-sap

Copy link
Copy Markdown
Author

Update after long time, as I've been (and still am) trying to fix a regression in test reliability...

The Configured condition is being updated at the end of reconcile(). If an error happens earlier in reconcile(), this part is never reached and the condition stays outdated. This caused tests to fail randomly, where one error in one resource's controller would cause a cascade of subsequent test case failures due to conditions not being updated. Especially tests and other logic that uses conditions.IsConfigured(), which checks if condition.ObservedGeneration matches the object's generation. Resources that reference other resources were more likely to fail, because the probabilities of failure in the referenced resources add up. For example BGPPeer which references VRF, BGP and RoutingPolicy. Overall failure rate was approx. 3-4 fails out of 10 runs of the full test suite.

My idea to fix this is to explicitly set the Configured condition to False or Unknown early in the reconcile() function. Therefore if it exits early due to an error, the condition will be left in a consistent state and its ObservedGeneration will be up-to-date. Only if all actions in reconcile() succeed, we get to the end and actually set the condition based on the result of Provider.EnsureXXX()

conditions.Set(s.BGPPeer, metav1.Condition{
	Type:   v1alpha1.ConfiguredCondition,
	Status: metav1.ConditionFalse,
})

// Controller code which may return early due to error...

err = s.Provider.EnsureBGPPeer(ctx, &provider.EnsureBGPPeerRequest{...})
cond := conditions.FromError(err)
conditions.Set(s.BGPPeer, cond)

This method has improved the test suite reliability to less than 1 failure out of 10 runs, but it's still not quite there. I will likely have to add this fix to all controllers that have the Configured condition.

Previously, some controllers did not set the Configured condition after
performing the configuration. They only set the Ready condition, which
was ambiguous. This PR explicitly sets the Configured condition based on
the provider success and ensures that the Ready condition is set
correctly at the end of the reconcile loop.

- Initialize the `ConfiguredCondition`
- Add deferred call of `conditions.RecomputeReady()` to ensure the Ready condition is evaluated and set at the end of the reconcile loop
- `cond := conditions.FromError(err)` already returns the Configured condition, so we just remove the next line that was overriding it with the Ready condition
- Check `Configured` condition on referenced resources
- Update the associated tests to check that the Configured condition has been set
- Add Kubebuilder printcolumn for the Configured condition

Some controllers depend on referenced resources. E.g. BGPPeer controller watches referenced BGP and VRF resources and triggers a self-reconciliation if their status changes. Since these resources now expose a proper Configured condition, we update the checking logic to use it instead of the Ready condition (which is now too broad)

Signed-off-by: Adam Trizuljak <adam.trizuljak@sap.com>
Signed-off-by: Adam Trizuljak <adam.trizuljak@sap.com>
Signed-off-by: Adam Trizuljak <adam.trizuljak@sap.com>
Signed-off-by: Adam Trizuljak <adam.trizuljak@sap.com>
Signed-off-by: Adam Trizuljak <adam.trizuljak@sap.com>
@adamtrizuljak-sap
adamtrizuljak-sap force-pushed the feat/configured-condition branch from 78339ed to 17ed13a Compare July 30, 2026 09:02
@github-actions

Copy link
Copy Markdown

Merging this branch will increase overall coverage

Impacted Packages Coverage Δ 🤖
github.com/ironcore-dev/network-operator/api/cisco/nx/v1alpha1 0.00% (ø)
github.com/ironcore-dev/network-operator/api/core/v1alpha1 1.78% (ø)
github.com/ironcore-dev/network-operator/internal/controller/cisco/nx 65.36% (+0.30%) 👍
github.com/ironcore-dev/network-operator/internal/controller/core 62.17% (+0.53%) 👍

Coverage by file

Changed files (no unit tests)

Changed File Coverage Δ Total Covered Missed 🤖
github.com/ironcore-dev/network-operator/api/cisco/nx/v1alpha1/bordergateway_types.go 0.00% (ø) 5 0 5
github.com/ironcore-dev/network-operator/api/cisco/nx/v1alpha1/system_types.go 0.00% (ø) 5 0 5
github.com/ironcore-dev/network-operator/api/core/v1alpha1/aaa_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/acl_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/banner_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/bgp_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/certificate_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/dhcprelay_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/dns_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/evpninstance_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/isis_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/managementaccess_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/ntp_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/pim_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/prefixset_types.go 10.00% (ø) 10 1 9
github.com/ironcore-dev/network-operator/api/core/v1alpha1/routingpolicy_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/snmp_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/syslog_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/user_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/vrf_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/internal/controller/cisco/nx/bordergateway_controller.go 53.59% (+0.62%) 237 (+1) 127 (+2) 110 (-1) 👍
github.com/ironcore-dev/network-operator/internal/controller/cisco/nx/system_controller.go 67.52% (+2.00%) 117 (+1) 79 (+3) 38 (-2) 👍
github.com/ironcore-dev/network-operator/internal/controller/core/aaa_controller.go 0.00% (ø) 140 (+1) 0 140 (+1)
github.com/ironcore-dev/network-operator/internal/controller/core/acl_controller.go 59.86% (+1.70%) 142 (+1) 85 (+3) 57 (-2) 👍
github.com/ironcore-dev/network-operator/internal/controller/core/banner_controller.go 59.41% (+1.42%) 170 (+1) 101 (+3) 69 (-2) 👍
github.com/ironcore-dev/network-operator/internal/controller/core/bgp_controller.go 70.29% (+1.09%) 239 (+2) 168 (+4) 71 (-2) 👍
github.com/ironcore-dev/network-operator/internal/controller/core/bgp_peer_controller.go 58.82% (+0.75%) 323 (+1) 190 (+3) 133 (-2) 👍
github.com/ironcore-dev/network-operator/internal/controller/core/certificate_controller.go 58.33% (-0.38%) 156 (+1) 91 65 (+1) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/dhcprelay_controller.go 66.15% (+0.26%) 260 (+2) 172 (+2) 88 👍
github.com/ironcore-dev/network-operator/internal/controller/core/dns_controller.go 61.87% (+0.28%) 139 (+1) 86 (+1) 53 👍
github.com/ironcore-dev/network-operator/internal/controller/core/evpninstance_controller.go 61.72% (+0.15%) 256 (+1) 158 (+1) 98 👍
github.com/ironcore-dev/network-operator/internal/controller/core/isis_controller.go 61.05% (+0.93%) 172 (-1) 105 (+1) 67 (-2) 👍
github.com/ironcore-dev/network-operator/internal/controller/core/managementaccess_controller.go 59.71% (+1.74%) 139 (+1) 83 (+3) 56 (-2) 👍
github.com/ironcore-dev/network-operator/internal/controller/core/ntp_controller.go 59.71% (+1.74%) 139 (+1) 83 (+3) 56 (-2) 👍
github.com/ironcore-dev/network-operator/internal/controller/core/pim_controller.go 61.05% (+1.40%) 172 (+1) 105 (+3) 67 (-2) 👍
github.com/ironcore-dev/network-operator/internal/controller/core/prefixset_controller.go 63.38% (+1.68%) 142 (+1) 90 (+3) 52 (-2) 👍
github.com/ironcore-dev/network-operator/internal/controller/core/routingpolicy_controller.go 67.88% (+0.34%) 193 (+2) 131 (+2) 62 👍
github.com/ironcore-dev/network-operator/internal/controller/core/snmp_controller.go 59.71% (+1.74%) 139 (+1) 83 (+3) 56 (-2) 👍
github.com/ironcore-dev/network-operator/internal/controller/core/syslog_controller.go 59.86% (+1.70%) 142 (+1) 85 (+3) 57 (-2) 👍
github.com/ironcore-dev/network-operator/internal/controller/core/user_controller.go 58.24% (+1.43%) 170 (+1) 99 (+3) 71 (-2) 👍
github.com/ironcore-dev/network-operator/internal/controller/core/vlan_controller.go 62.25% (+0.25%) 151 (+1) 94 (+1) 57 👍
github.com/ironcore-dev/network-operator/internal/controller/core/vrf_controller.go 62.86% (+0.54%) 140 (+2) 88 (+2) 52 👍

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

Changed unit test files

  • github.com/ironcore-dev/network-operator/internal/controller/cisco/nx/bordergateway_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/cisco/nx/system_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/acl_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/banner_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/bgp_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/bgp_peer_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/certificate_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/dhcprelay_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/dns_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/evpninstance_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/isis_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/managementaccess_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/ntp_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/pim_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/prefixset_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/routingpolicy_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/snmp_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/suite_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/syslog_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/user_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/vlan_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/vrf_controller_test.go

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants