diff --git a/api/cisco/nx/v1alpha1/bordergateway_types.go b/api/cisco/nx/v1alpha1/bordergateway_types.go index 9f1b02202..f1aa2756a 100644 --- a/api/cisco/nx/v1alpha1/bordergateway_types.go +++ b/api/cisco/nx/v1alpha1/bordergateway_types.go @@ -167,6 +167,7 @@ type BorderGatewayStatus struct { // +kubebuilder:printcolumn:name="Admin State",type=string,JSONPath=`.spec.adminState` // +kubebuilder:printcolumn:name="Source Interface",type=string,JSONPath=`.spec.sourceInterfaceRef.name` // +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" diff --git a/api/cisco/nx/v1alpha1/system_types.go b/api/cisco/nx/v1alpha1/system_types.go index 12e671e37..b33704359 100644 --- a/api/cisco/nx/v1alpha1/system_types.go +++ b/api/cisco/nx/v1alpha1/system_types.go @@ -61,6 +61,7 @@ type SystemStatus struct { // +kubebuilder:resource:shortName=nxsystem // +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name` // +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" diff --git a/api/core/v1alpha1/aaa_types.go b/api/core/v1alpha1/aaa_types.go index ab6b61e43..0564627f6 100644 --- a/api/core/v1alpha1/aaa_types.go +++ b/api/core/v1alpha1/aaa_types.go @@ -230,6 +230,7 @@ type AAAStatus struct { // +kubebuilder:resource:singular=aaa // +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name` // +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="Age",type="date",JSONPath=".metadata.creationTimestamp" // AAA is the Schema for the aaa API diff --git a/api/core/v1alpha1/acl_types.go b/api/core/v1alpha1/acl_types.go index 6501f3625..a7a01b708 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" diff --git a/api/core/v1alpha1/banner_types.go b/api/core/v1alpha1/banner_types.go index e9de15b87..25a8cdbaa 100644 --- a/api/core/v1alpha1/banner_types.go +++ b/api/core/v1alpha1/banner_types.go @@ -67,6 +67,7 @@ type BannerStatus struct { // +kubebuilder:printcolumn:name="Type",type=string,JSONPath=`.spec.type` // +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name` // +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" diff --git a/api/core/v1alpha1/bgp_types.go b/api/core/v1alpha1/bgp_types.go index 15c509116..32aa66dff 100644 --- a/api/core/v1alpha1/bgp_types.go +++ b/api/core/v1alpha1/bgp_types.go @@ -182,6 +182,7 @@ type BGPStatus struct { // +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name` // +kubebuilder:printcolumn:name="Admin State",type=string,JSONPath=`.spec.adminState` // +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" diff --git a/api/core/v1alpha1/certificate_types.go b/api/core/v1alpha1/certificate_types.go index 5d0093d79..042bf4644 100644 --- a/api/core/v1alpha1/certificate_types.go +++ b/api/core/v1alpha1/certificate_types.go @@ -57,6 +57,7 @@ type CertificateStatus struct { // +kubebuilder:printcolumn:name="Certificate",type=string,JSONPath=`.spec.id` // +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name` // +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" diff --git a/api/core/v1alpha1/dhcprelay_types.go b/api/core/v1alpha1/dhcprelay_types.go index a418efd8f..21ff93172 100644 --- a/api/core/v1alpha1/dhcprelay_types.go +++ b/api/core/v1alpha1/dhcprelay_types.go @@ -75,6 +75,7 @@ type DHCPRelayStatus struct { // +kubebuilder:resource:singular=dhcprelay // +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name` // +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="Age",type="date",JSONPath=".metadata.creationTimestamp" // DHCPRelay is the Schema for the DHCPRelays API diff --git a/api/core/v1alpha1/dns_types.go b/api/core/v1alpha1/dns_types.go index 509579acf..0cb9f1747 100644 --- a/api/core/v1alpha1/dns_types.go +++ b/api/core/v1alpha1/dns_types.go @@ -83,6 +83,7 @@ type DNSStatus struct { // +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name` // +kubebuilder:printcolumn:name="Admin State",type=string,JSONPath=`.spec.adminState` // +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" diff --git a/api/core/v1alpha1/evpninstance_types.go b/api/core/v1alpha1/evpninstance_types.go index d38fb01b7..75a1f62fd 100644 --- a/api/core/v1alpha1/evpninstance_types.go +++ b/api/core/v1alpha1/evpninstance_types.go @@ -133,6 +133,7 @@ type EVPNInstanceStatus struct { // +kubebuilder:printcolumn:name="Type",type=string,JSONPath=`.spec.type` // +kubebuilder:printcolumn:name="Route Distinguisher",type=string,JSONPath=`.spec.routeDistinguisher`,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" diff --git a/api/core/v1alpha1/isis_types.go b/api/core/v1alpha1/isis_types.go index 3a3c17da2..30165e3ef 100644 --- a/api/core/v1alpha1/isis_types.go +++ b/api/core/v1alpha1/isis_types.go @@ -112,6 +112,7 @@ type ISISStatus struct { // +kubebuilder:printcolumn:name="NET",type=string,JSONPath=`.spec.networkEntityTitle` // +kubebuilder:printcolumn:name="Level",type=string,JSONPath=`.spec.type`,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" diff --git a/api/core/v1alpha1/managementaccess_types.go b/api/core/v1alpha1/managementaccess_types.go index 8f5473bfd..4cad4945b 100644 --- a/api/core/v1alpha1/managementaccess_types.go +++ b/api/core/v1alpha1/managementaccess_types.go @@ -140,6 +140,7 @@ type ManagementAccessStatus struct { // +kubebuilder:printcolumn:name="gRPC",type=boolean,JSONPath=`.spec.grpc.enabled` // +kubebuilder:printcolumn:name="gRPC Port",type=integer,JSONPath=`.spec.grpc.port`,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" diff --git a/api/core/v1alpha1/ntp_types.go b/api/core/v1alpha1/ntp_types.go index f6ffaddc9..bd7cc20cd 100644 --- a/api/core/v1alpha1/ntp_types.go +++ b/api/core/v1alpha1/ntp_types.go @@ -80,6 +80,7 @@ type NTPStatus struct { // +kubebuilder:printcolumn:name="Admin State",type=string,JSONPath=`.spec.adminState` // +kubebuilder:printcolumn:name="Source Interface",type=string,JSONPath=`.spec.sourceInterfaceName` // +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" diff --git a/api/core/v1alpha1/pim_types.go b/api/core/v1alpha1/pim_types.go index e3ed5e299..5acd27c26 100644 --- a/api/core/v1alpha1/pim_types.go +++ b/api/core/v1alpha1/pim_types.go @@ -96,6 +96,7 @@ type PIMStatus struct { // +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name` // +kubebuilder:printcolumn:name="Admin State",type=string,JSONPath=`.spec.adminState` // +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" diff --git a/api/core/v1alpha1/prefixset_types.go b/api/core/v1alpha1/prefixset_types.go index f80d433ce..2ec64f895 100644 --- a/api/core/v1alpha1/prefixset_types.go +++ b/api/core/v1alpha1/prefixset_types.go @@ -102,6 +102,7 @@ type PrefixSetStatus 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" diff --git a/api/core/v1alpha1/routingpolicy_types.go b/api/core/v1alpha1/routingpolicy_types.go index da6ba9366..da9c9b5dc 100644 --- a/api/core/v1alpha1/routingpolicy_types.go +++ b/api/core/v1alpha1/routingpolicy_types.go @@ -209,6 +209,7 @@ type RoutingPolicyStatus struct { // +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name` // +kubebuilder:printcolumn:name="Statements",type=string,JSONPath=`.status.statementsSummary`,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" diff --git a/api/core/v1alpha1/snmp_types.go b/api/core/v1alpha1/snmp_types.go index 47dabca9c..4f51046b1 100644 --- a/api/core/v1alpha1/snmp_types.go +++ b/api/core/v1alpha1/snmp_types.go @@ -134,6 +134,7 @@ type SNMPStatus struct { // +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name` // +kubebuilder:printcolumn:name="Source Interface",type=string,JSONPath=`.spec.sourceInterfaceName` // +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" diff --git a/api/core/v1alpha1/syslog_types.go b/api/core/v1alpha1/syslog_types.go index ad4de53cb..5b7fd6b9c 100644 --- a/api/core/v1alpha1/syslog_types.go +++ b/api/core/v1alpha1/syslog_types.go @@ -110,6 +110,7 @@ type SyslogStatus struct { // +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name` // +kubebuilder:printcolumn:name="Servers",type=string,JSONPath=`.status.serversSummary`,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" diff --git a/api/core/v1alpha1/user_types.go b/api/core/v1alpha1/user_types.go index 5f2b05f02..85a43d154 100644 --- a/api/core/v1alpha1/user_types.go +++ b/api/core/v1alpha1/user_types.go @@ -90,6 +90,7 @@ type UserStatus struct { // +kubebuilder:printcolumn:name="Username",type=string,JSONPath=`.spec.username` // +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name` // +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" diff --git a/api/core/v1alpha1/vrf_types.go b/api/core/v1alpha1/vrf_types.go index af9d125f3..f5fd9e9a3 100644 --- a/api/core/v1alpha1/vrf_types.go +++ b/api/core/v1alpha1/vrf_types.go @@ -127,6 +127,7 @@ type VRFStatus struct { // +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name` // +kubebuilder:printcolumn:name="Route Distinguisher",type=string,JSONPath=`.spec.routeDistinguisher`,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" diff --git a/charts/network-operator/templates/crd/aaa.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/aaa.networking.metal.ironcore.dev.yaml index 6618110cb..7a1f1d2b4 100644 --- a/charts/network-operator/templates/crd/aaa.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/aaa.networking.metal.ironcore.dev.yaml @@ -24,6 +24,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .metadata.creationTimestamp name: Age type: date diff --git a/charts/network-operator/templates/crd/accesscontrollists.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/accesscontrollists.networking.metal.ironcore.dev.yaml index 522a48dc4..8a6e0103a 100644 --- a/charts/network-operator/templates/crd/accesscontrollists.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/accesscontrollists.networking.metal.ironcore.dev.yaml @@ -33,6 +33,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/banners.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/banners.networking.metal.ironcore.dev.yaml index 6de5a6b63..ff72bc336 100644 --- a/charts/network-operator/templates/crd/banners.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/banners.networking.metal.ironcore.dev.yaml @@ -27,6 +27,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/bgp.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/bgp.networking.metal.ironcore.dev.yaml index 8f00271f0..c778f5b4e 100644 --- a/charts/network-operator/templates/crd/bgp.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/bgp.networking.metal.ironcore.dev.yaml @@ -33,6 +33,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/bordergateways.nx.cisco.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/bordergateways.nx.cisco.networking.metal.ironcore.dev.yaml index 3f5d964f0..a422ea6fe 100644 --- a/charts/network-operator/templates/crd/bordergateways.nx.cisco.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/bordergateways.nx.cisco.networking.metal.ironcore.dev.yaml @@ -35,6 +35,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/certificates.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/certificates.networking.metal.ironcore.dev.yaml index 131841c66..dc891f7cf 100644 --- a/charts/network-operator/templates/crd/certificates.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/certificates.networking.metal.ironcore.dev.yaml @@ -30,6 +30,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/dhcprelays.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/dhcprelays.networking.metal.ironcore.dev.yaml index e6b75612b..3d80d5150 100644 --- a/charts/network-operator/templates/crd/dhcprelays.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/dhcprelays.networking.metal.ironcore.dev.yaml @@ -24,6 +24,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .metadata.creationTimestamp name: Age type: date diff --git a/charts/network-operator/templates/crd/dns.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/dns.networking.metal.ironcore.dev.yaml index 13627661f..ec90afc26 100644 --- a/charts/network-operator/templates/crd/dns.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/dns.networking.metal.ironcore.dev.yaml @@ -30,6 +30,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/evpninstances.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/evpninstances.networking.metal.ironcore.dev.yaml index 519d3d2d4..bbea74a83 100644 --- a/charts/network-operator/templates/crd/evpninstances.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/evpninstances.networking.metal.ironcore.dev.yaml @@ -37,6 +37,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/isis.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/isis.networking.metal.ironcore.dev.yaml index 29ed18f46..f4529f6db 100644 --- a/charts/network-operator/templates/crd/isis.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/isis.networking.metal.ironcore.dev.yaml @@ -37,6 +37,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/managementaccesses.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/managementaccesses.networking.metal.ironcore.dev.yaml index 22c23c81f..99527c9ed 100644 --- a/charts/network-operator/templates/crd/managementaccesses.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/managementaccesses.networking.metal.ironcore.dev.yaml @@ -37,6 +37,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/ntp.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/ntp.networking.metal.ironcore.dev.yaml index caf783013..7453bdb82 100644 --- a/charts/network-operator/templates/crd/ntp.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/ntp.networking.metal.ironcore.dev.yaml @@ -30,6 +30,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/pim.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/pim.networking.metal.ironcore.dev.yaml index 31b2dbc30..23d2dca9a 100644 --- a/charts/network-operator/templates/crd/pim.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/pim.networking.metal.ironcore.dev.yaml @@ -27,6 +27,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/prefixsets.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/prefixsets.networking.metal.ironcore.dev.yaml index 483e400fe..715109f7a 100644 --- a/charts/network-operator/templates/crd/prefixsets.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/prefixsets.networking.metal.ironcore.dev.yaml @@ -31,6 +31,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/routingpolicies.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/routingpolicies.networking.metal.ironcore.dev.yaml index e35f4c87c..70913edc2 100644 --- a/charts/network-operator/templates/crd/routingpolicies.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/routingpolicies.networking.metal.ironcore.dev.yaml @@ -33,6 +33,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/snmp.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/snmp.networking.metal.ironcore.dev.yaml index e387619a6..7cd403e25 100644 --- a/charts/network-operator/templates/crd/snmp.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/snmp.networking.metal.ironcore.dev.yaml @@ -27,6 +27,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/syslogs.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/syslogs.networking.metal.ironcore.dev.yaml index c2aaec59f..8fba96d0f 100644 --- a/charts/network-operator/templates/crd/syslogs.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/syslogs.networking.metal.ironcore.dev.yaml @@ -28,6 +28,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/systems.nx.cisco.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/systems.nx.cisco.networking.metal.ironcore.dev.yaml index d7d9c2661..5acc30ffb 100644 --- a/charts/network-operator/templates/crd/systems.nx.cisco.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/systems.nx.cisco.networking.metal.ironcore.dev.yaml @@ -26,6 +26,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/users.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/users.networking.metal.ironcore.dev.yaml index ceb20bd9c..93571de9c 100644 --- a/charts/network-operator/templates/crd/users.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/users.networking.metal.ironcore.dev.yaml @@ -27,6 +27,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/charts/network-operator/templates/crd/vrfs.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/vrfs.networking.metal.ironcore.dev.yaml index c377a8eb3..a0e4f778c 100644 --- a/charts/network-operator/templates/crd/vrfs.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/vrfs.networking.metal.ironcore.dev.yaml @@ -31,6 +31,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_aaa.yaml b/config/crd/bases/networking.metal.ironcore.dev_aaa.yaml index 1f03feb52..e8c01aa4c 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_aaa.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_aaa.yaml @@ -21,6 +21,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .metadata.creationTimestamp name: Age type: date diff --git a/config/crd/bases/networking.metal.ironcore.dev_accesscontrollists.yaml b/config/crd/bases/networking.metal.ironcore.dev_accesscontrollists.yaml index 39480b6f7..7a431766b 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_accesscontrollists.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_accesscontrollists.yaml @@ -30,6 +30,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_banners.yaml b/config/crd/bases/networking.metal.ironcore.dev_banners.yaml index 009b9edba..467e8466e 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_banners.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_banners.yaml @@ -24,6 +24,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_bgp.yaml b/config/crd/bases/networking.metal.ironcore.dev_bgp.yaml index 8a1780f75..f7710f095 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_bgp.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_bgp.yaml @@ -30,6 +30,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_certificates.yaml b/config/crd/bases/networking.metal.ironcore.dev_certificates.yaml index 17bfe94ab..c33a338d5 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_certificates.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_certificates.yaml @@ -27,6 +27,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_dhcprelays.yaml b/config/crd/bases/networking.metal.ironcore.dev_dhcprelays.yaml index 48cefc42c..44b9f2232 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_dhcprelays.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_dhcprelays.yaml @@ -21,6 +21,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .metadata.creationTimestamp name: Age type: date diff --git a/config/crd/bases/networking.metal.ironcore.dev_dns.yaml b/config/crd/bases/networking.metal.ironcore.dev_dns.yaml index 9b66a3a11..7401504a8 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_dns.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_dns.yaml @@ -27,6 +27,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_evpninstances.yaml b/config/crd/bases/networking.metal.ironcore.dev_evpninstances.yaml index 8ee981b5f..b2e8f4b67 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_evpninstances.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_evpninstances.yaml @@ -34,6 +34,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_isis.yaml b/config/crd/bases/networking.metal.ironcore.dev_isis.yaml index 00428b26b..91341fc8d 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_isis.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_isis.yaml @@ -34,6 +34,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_managementaccesses.yaml b/config/crd/bases/networking.metal.ironcore.dev_managementaccesses.yaml index 94ffbe6ab..5802f5f3d 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_managementaccesses.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_managementaccesses.yaml @@ -34,6 +34,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_ntp.yaml b/config/crd/bases/networking.metal.ironcore.dev_ntp.yaml index 184698a73..d4dc2e6c0 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_ntp.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_ntp.yaml @@ -27,6 +27,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_pim.yaml b/config/crd/bases/networking.metal.ironcore.dev_pim.yaml index 1851dcc72..80688d95f 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_pim.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_pim.yaml @@ -24,6 +24,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_prefixsets.yaml b/config/crd/bases/networking.metal.ironcore.dev_prefixsets.yaml index 71fd6800c..dddd3e146 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_prefixsets.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_prefixsets.yaml @@ -28,6 +28,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_routingpolicies.yaml b/config/crd/bases/networking.metal.ironcore.dev_routingpolicies.yaml index ac932b49b..669f7fb1a 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_routingpolicies.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_routingpolicies.yaml @@ -30,6 +30,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_snmp.yaml b/config/crd/bases/networking.metal.ironcore.dev_snmp.yaml index 062e4955a..5e6c685c6 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_snmp.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_snmp.yaml @@ -24,6 +24,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_syslogs.yaml b/config/crd/bases/networking.metal.ironcore.dev_syslogs.yaml index 114680bfe..cc6ce41a4 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_syslogs.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_syslogs.yaml @@ -25,6 +25,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_users.yaml b/config/crd/bases/networking.metal.ironcore.dev_users.yaml index e0efe19f0..8bc8d0447 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_users.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_users.yaml @@ -24,6 +24,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/networking.metal.ironcore.dev_vrfs.yaml b/config/crd/bases/networking.metal.ironcore.dev_vrfs.yaml index 535cd7b04..7695980aa 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_vrfs.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_vrfs.yaml @@ -28,6 +28,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/nx.cisco.networking.metal.ironcore.dev_bordergateways.yaml b/config/crd/bases/nx.cisco.networking.metal.ironcore.dev_bordergateways.yaml index 54496856e..4c2aac415 100644 --- a/config/crd/bases/nx.cisco.networking.metal.ironcore.dev_bordergateways.yaml +++ b/config/crd/bases/nx.cisco.networking.metal.ironcore.dev_bordergateways.yaml @@ -32,6 +32,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/config/crd/bases/nx.cisco.networking.metal.ironcore.dev_systems.yaml b/config/crd/bases/nx.cisco.networking.metal.ironcore.dev_systems.yaml index 2a03f32b8..5b39f3390 100644 --- a/config/crd/bases/nx.cisco.networking.metal.ironcore.dev_systems.yaml +++ b/config/crd/bases/nx.cisco.networking.metal.ironcore.dev_systems.yaml @@ -23,6 +23,10 @@ spec: - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=="Configured")].status + name: Configured + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Paused")].status name: Paused priority: 1 diff --git a/internal/controller/cisco/nx/bordergateway_controller.go b/internal/controller/cisco/nx/bordergateway_controller.go index 1e9b2324f..44d77dae1 100644 --- a/internal/controller/cisco/nx/bordergateway_controller.go +++ b/internal/controller/cisco/nx/bordergateway_controller.go @@ -165,7 +165,7 @@ func (r *BorderGatewayReconciler) Reconcile(ctx context.Context, req ctrl.Reques } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -327,6 +327,10 @@ func (r *BorderGatewayReconciler) reconcile(ctx context.Context, s *borderGatewa s.BorderGateway.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.BorderGateway) + }() + // Ensure the BorderGateway is owned by the Device. if !controllerutil.HasControllerReference(s.BorderGateway) { if err := controllerutil.SetOwnerReference(s.Device, s.BorderGateway, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -367,8 +371,6 @@ func (r *BorderGatewayReconciler) reconcile(ctx context.Context, s *borderGatewa }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.BorderGateway, cond) return err @@ -386,7 +388,7 @@ func (r *BorderGatewayReconciler) reconcileSourceInterface(ctx context.Context, if err := r.Get(ctx, key, intf); err != nil { if apierrors.IsNotFound(err) { conditions.Set(s.BorderGateway, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.InterfaceNotFoundReason, Message: fmt.Sprintf("source interface %q not found", key), @@ -398,7 +400,7 @@ func (r *BorderGatewayReconciler) reconcileSourceInterface(ctx context.Context, if intf.Spec.DeviceRef.Name != s.Device.Name { conditions.Set(s.BorderGateway, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.CrossDeviceReferenceReason, Message: fmt.Sprintf("source interface %q does not belong to device %q", intf.Name, s.Device.Name), @@ -408,7 +410,7 @@ func (r *BorderGatewayReconciler) reconcileSourceInterface(ctx context.Context, if intf.Spec.Type != v1alpha1.InterfaceTypeLoopback { conditions.Set(s.BorderGateway, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.InvalidInterfaceTypeReason, Message: fmt.Sprintf("source interface %q is not of type Loopback, got %q", intf.Name, intf.Spec.Type), @@ -427,7 +429,7 @@ func (r *BorderGatewayReconciler) reconcileInterconnectInterfaces(ctx context.Co if err := r.Get(ctx, client.ObjectKey{Name: ref.Name, Namespace: s.BorderGateway.Namespace}, intf); err != nil { if apierrors.IsNotFound(err) { conditions.Set(s.BorderGateway, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.InterfaceNotFoundReason, Message: fmt.Sprintf("interconnect interface %q not found", ref.Name), @@ -439,7 +441,7 @@ func (r *BorderGatewayReconciler) reconcileInterconnectInterfaces(ctx context.Co if intf.Spec.DeviceRef.Name != s.Device.Name { conditions.Set(s.BorderGateway, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.CrossDeviceReferenceReason, Message: fmt.Sprintf("interconnect interface %q does not belong to device %q", intf.Name, s.Device.Name), @@ -449,7 +451,7 @@ func (r *BorderGatewayReconciler) reconcileInterconnectInterfaces(ctx context.Co if intf.Spec.Type != v1alpha1.InterfaceTypePhysical { conditions.Set(s.BorderGateway, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.InvalidInterfaceTypeReason, Message: fmt.Sprintf("interconnect interface %q is not of type Physical, got %q", intf.Name, intf.Spec.Type), @@ -474,7 +476,7 @@ func (r *BorderGatewayReconciler) reconcileBGPPeers(ctx context.Context, s *bord if err := r.Get(ctx, client.ObjectKey{Name: ref.Name, Namespace: s.BorderGateway.Namespace}, peer); err != nil { if apierrors.IsNotFound(err) { conditions.Set(s.BorderGateway, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.BGPPeerNotFoundReason, Message: fmt.Sprintf("BGP peer %q not found", ref.Name), @@ -486,7 +488,7 @@ func (r *BorderGatewayReconciler) reconcileBGPPeers(ctx context.Context, s *bord if peer.Spec.DeviceRef.Name != s.Device.Name { conditions.Set(s.BorderGateway, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.CrossDeviceReferenceReason, Message: fmt.Sprintf("BGP peer %q does not belong to device %q", peer.Name, s.Device.Name), diff --git a/internal/controller/cisco/nx/bordergateway_controller_test.go b/internal/controller/cisco/nx/bordergateway_controller_test.go index d6a8ec9c5..f6f3c157f 100644 --- a/internal/controller/cisco/nx/bordergateway_controller_test.go +++ b/internal/controller/cisco/nx/bordergateway_controller_test.go @@ -122,11 +122,13 @@ var _ = Describe("BorderGateway Controller", func() { Eventually(func(g Gomega) { resource := &nxv1alpha1.BorderGateway{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") diff --git a/internal/controller/cisco/nx/system_controller.go b/internal/controller/cisco/nx/system_controller.go index 58551fea2..6b4735027 100644 --- a/internal/controller/cisco/nx/system_controller.go +++ b/internal/controller/cisco/nx/system_controller.go @@ -162,7 +162,7 @@ func (r *SystemReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ c } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -247,6 +247,10 @@ func (r *SystemReconciler) reconcile(ctx context.Context, s *systemScope) (reter s.System.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.System) + }() + // Ensure the System is owned by the Device. if !controllerutil.HasControllerReference(s.System) { if err := controllerutil.SetOwnerReference(s.Device, s.System, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -267,8 +271,6 @@ func (r *SystemReconciler) reconcile(ctx context.Context, s *systemScope) (reter err := s.Provider.EnsureSystemSettings(ctx, s.System) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.System, cond) return err diff --git a/internal/controller/cisco/nx/system_controller_test.go b/internal/controller/cisco/nx/system_controller_test.go index ff04a99a6..1fd12cae4 100644 --- a/internal/controller/cisco/nx/system_controller_test.go +++ b/internal/controller/cisco/nx/system_controller_test.go @@ -101,11 +101,13 @@ var _ = Describe("System Controller", func() { Eventually(func(g Gomega) { resource := &nxv1alpha1.System{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") diff --git a/internal/controller/core/aaa_controller.go b/internal/controller/core/aaa_controller.go index c38b1061e..fdb866512 100644 --- a/internal/controller/core/aaa_controller.go +++ b/internal/controller/core/aaa_controller.go @@ -170,7 +170,7 @@ func (r *AAAReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -242,6 +242,10 @@ func (r *AAAReconciler) reconcile(ctx context.Context, s *aaaScope) (reterr erro s.AAA.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.AAA) + }() + // Ensure the AAA is owned by the Device. if !controllerutil.HasControllerReference(s.AAA) { if err := controllerutil.SetOwnerReference(s.Device, s.AAA, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -290,8 +294,6 @@ func (r *AAAReconciler) reconcile(ctx context.Context, s *aaaScope) (reterr erro }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.AAA, cond) return err diff --git a/internal/controller/core/acl_controller.go b/internal/controller/core/acl_controller.go index 77510b9bd..b3a39c971 100644 --- a/internal/controller/core/acl_controller.go +++ b/internal/controller/core/acl_controller.go @@ -172,7 +172,7 @@ func (r *AccessControlListReconciler) Reconcile(ctx context.Context, req ctrl.Re } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -271,6 +271,10 @@ func (r *AccessControlListReconciler) reconcile(ctx context.Context, s *aclScope s.ACL.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.ACL) + }() + // Ensure the AccessControlList is owned by the Device. if !controllerutil.HasControllerReference(s.ACL) { if err := controllerutil.SetOwnerReference(s.Device, s.ACL, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -300,8 +304,6 @@ func (r *AccessControlListReconciler) reconcile(ctx context.Context, s *aclScope }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.ACL, cond) return err diff --git a/internal/controller/core/acl_controller_test.go b/internal/controller/core/acl_controller_test.go index 45718d5af..476cf0eed 100644 --- a/internal/controller/core/acl_controller_test.go +++ b/internal/controller/core/acl_controller_test.go @@ -118,11 +118,13 @@ var _ = Describe("AccessControlList Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.AccessControlList{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") diff --git a/internal/controller/core/banner_controller.go b/internal/controller/core/banner_controller.go index 9e474648e..9aaf4f770 100644 --- a/internal/controller/core/banner_controller.go +++ b/internal/controller/core/banner_controller.go @@ -176,7 +176,7 @@ func (r *BannerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ c } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -287,6 +287,10 @@ func (r *BannerReconciler) reconcile(ctx context.Context, s *bannerScope) (reter s.Banner.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.Banner) + }() + // Ensure the Banner is owned by the Device. if !controllerutil.HasControllerReference(s.Banner) { if err := controllerutil.SetOwnerReference(s.Device, s.Banner, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -316,8 +320,6 @@ func (r *BannerReconciler) reconcile(ctx context.Context, s *bannerScope) (reter }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.Banner, cond) return err diff --git a/internal/controller/core/banner_controller_test.go b/internal/controller/core/banner_controller_test.go index 411ccf2d4..4527a5e11 100644 --- a/internal/controller/core/banner_controller_test.go +++ b/internal/controller/core/banner_controller_test.go @@ -102,11 +102,13 @@ var _ = Describe("Banner Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.Banner{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") @@ -163,11 +165,13 @@ var _ = Describe("Banner Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.Banner{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") diff --git a/internal/controller/core/bgp_controller.go b/internal/controller/core/bgp_controller.go index 58e1f6892..7e9a9893e 100644 --- a/internal/controller/core/bgp_controller.go +++ b/internal/controller/core/bgp_controller.go @@ -185,7 +185,7 @@ func (r *BGPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -308,7 +308,7 @@ func (r *BGPReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager) UpdateFunc: func(e event.UpdateEvent) bool { oldVRF := e.ObjectOld.(*v1alpha1.VRF) newVRF := e.ObjectNew.(*v1alpha1.VRF) - return conditions.IsReady(oldVRF) != conditions.IsReady(newVRF) + return conditions.IsConfigured(oldVRF) != conditions.IsConfigured(newVRF) }, GenericFunc: func(e event.GenericEvent) bool { return false @@ -348,6 +348,10 @@ func (r *BGPReconciler) reconcile(ctx context.Context, s *bgpScope) (reterr erro s.BGP.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.BGP) + }() + // Ensure the BGP is owned by the Device. if !controllerutil.HasControllerReference(s.BGP) { if err := controllerutil.SetOwnerReference(s.Device, s.BGP, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -390,8 +394,6 @@ func (r *BGPReconciler) reconcile(ctx context.Context, s *bgpScope) (reterr erro }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.BGP, cond) return err @@ -443,7 +445,7 @@ func (r *BGPReconciler) reconcileVRF(ctx context.Context, bgp *v1alpha1.BGP, dev }, vrf); err != nil { if apierrors.IsNotFound(err) { conditions.Set(bgp, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.VRFNotFoundReason, Message: fmt.Sprintf("VRF %s not found", bgp.Spec.VrfRef.Name), @@ -454,7 +456,7 @@ func (r *BGPReconciler) reconcileVRF(ctx context.Context, bgp *v1alpha1.BGP, dev } if vrf.Spec.DeviceRef.Name != device.Name { conditions.Set(bgp, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.CrossDeviceReferenceReason, Message: fmt.Sprintf("VRF %s belongs to device %s, not %s", bgp.Spec.VrfRef.Name, vrf.Spec.DeviceRef.Name, device.Name), @@ -462,10 +464,10 @@ func (r *BGPReconciler) reconcileVRF(ctx context.Context, bgp *v1alpha1.BGP, dev return nil, reconcile.TerminalError(fmt.Errorf("vrf %s belongs to different device", bgp.Spec.VrfRef.Name)) } - if !conditions.IsReady(vrf) { + if !conditions.IsConfigured(vrf) { // VRF uses ReadyCondition as its top-level configured state (no separate ConfiguredCondition). conditions.Set(bgp, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.WaitingForDependenciesReason, Message: fmt.Sprintf("Waiting for VRF %s to become ready", bgp.Spec.VrfRef.Name), @@ -497,7 +499,7 @@ func (r *BGPReconciler) reconcileRedistributeDirectPolicies(ctx context.Context, if err := r.Get(ctx, types.NamespacedName{Name: ref.Name, Namespace: bgp.Namespace}, rp); err != nil { if apierrors.IsNotFound(err) { conditions.Set(bgp, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.WaitingForDependenciesReason, Message: fmt.Sprintf("RoutingPolicy %s not found", ref.Name), @@ -509,7 +511,7 @@ func (r *BGPReconciler) reconcileRedistributeDirectPolicies(ctx context.Context, if rp.Spec.DeviceRef.Name != device.Name { conditions.Set(bgp, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.CrossDeviceReferenceReason, Message: fmt.Sprintf("RoutingPolicy %s belongs to device %s, not %s", ref.Name, rp.Spec.DeviceRef.Name, device.Name), diff --git a/internal/controller/core/bgp_controller_test.go b/internal/controller/core/bgp_controller_test.go index 2a70a6c2e..34e7e0d25 100644 --- a/internal/controller/core/bgp_controller_test.go +++ b/internal/controller/core/bgp_controller_test.go @@ -33,6 +33,12 @@ var _ = Describe("BGP Controller", func() { }, } Expect(k8sClient.Create(ctx, device)).To(Succeed()) + + By("Waiting for the Device to be created") + Eventually(func(g Gomega) { + resource := &v1alpha1.Device{} + g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(device), resource)).To(Succeed()) + }).Should(Succeed()) }) AfterEach(func() { @@ -115,11 +121,13 @@ var _ = Describe("BGP Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.BGP{} g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(bgp), resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") @@ -144,11 +152,18 @@ var _ = Describe("BGP Controller", func() { } Expect(k8sClient.Create(ctx, bgp)).To(Succeed()) - By("Expecting ReadyCondition to be False with VRFNotFoundReason reason") + By("Waiting for BGP's condition to be fully consistent") Eventually(func(g Gomega) { resource := &v1alpha1.BGP{} g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(bgp), resource)).To(Succeed()) - cond := conditions.Get(resource, v1alpha1.ReadyCondition) + g.Expect(conditions.IsConfigured(resource)).To(BeFalse()) // checks ObservedGeneration too + }).Should(Succeed()) + + By("Expecting ConfiguredCondition to be False with VRFNotFoundReason reason") + Eventually(func(g Gomega) { + resource := &v1alpha1.BGP{} + g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(bgp), resource)).To(Succeed()) + cond := conditions.Get(resource, v1alpha1.ConfiguredCondition) g.Expect(cond).ToNot(BeNil()) g.Expect(cond.Status).To(Equal(metav1.ConditionFalse)) g.Expect(cond.Reason).To(Equal(v1alpha1.VRFNotFoundReason)) @@ -223,11 +238,11 @@ var _ = Describe("BGP Controller", func() { } Expect(k8sClient.Create(ctx, bgp)).To(Succeed()) - By("Expecting ReadyCondition to be False with WaitingForDependencies reason") + By("Expecting ConfiguredCondition to be False with WaitingForDependencies reason") Eventually(func(g Gomega) { resource := &v1alpha1.BGP{} g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(bgp), resource)).To(Succeed()) - cond := conditions.Get(resource, v1alpha1.ReadyCondition) + cond := conditions.Get(resource, v1alpha1.ConfiguredCondition) g.Expect(cond).ToNot(BeNil()) g.Expect(cond.Status).To(Equal(metav1.ConditionFalse)) g.Expect(cond.Reason).To(Equal(v1alpha1.WaitingForDependenciesReason)) diff --git a/internal/controller/core/bgp_peer_controller.go b/internal/controller/core/bgp_peer_controller.go index 72ec7ee4d..23e373a4e 100644 --- a/internal/controller/core/bgp_peer_controller.go +++ b/internal/controller/core/bgp_peer_controller.go @@ -47,6 +47,9 @@ const bgpPeerBGPRefIndexKey = ".spec.bgpRef.name" // referenced by BGPPeer address families. const bgpPeerRoutingPolicyRefIndexKey = ".spec.addressFamilies.routingPolicyRefs" +// bgpPeerInterfaceRefIndexKey is the field index key for BGPPeer.Spec.LocalAddress.InterfaceRef.Name. +const bgpPeerInterfaceRefIndexKey = ".spec.localAddress.interfaceRef.name" + // BGPPeerReconciler reconciles a BGPPeer object type BGPPeerReconciler struct { client.Client @@ -275,6 +278,16 @@ func (r *BGPPeerReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manag return err } + if err := mgr.GetFieldIndexer().IndexField(ctx, &v1alpha1.BGPPeer{}, bgpPeerInterfaceRefIndexKey, func(obj client.Object) []string { + o := obj.(*v1alpha1.BGPPeer) + if o.Spec.LocalAddress == nil { + return nil + } + return []string{o.Spec.LocalAddress.InterfaceRef.Name} + }); err != nil { + return err + } + bldr := ctrl.NewControllerManagedBy(mgr). For(&v1alpha1.BGPPeer{}). Named("bgppeer"). @@ -315,7 +328,7 @@ func (r *BGPPeerReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manag UpdateFunc: func(e event.UpdateEvent) bool { oldBGP := e.ObjectOld.(*v1alpha1.BGP) newBGP := e.ObjectNew.(*v1alpha1.BGP) - return conditions.IsReady(oldBGP) != conditions.IsReady(newBGP) + return conditions.IsConfigured(oldBGP) != conditions.IsConfigured(newBGP) }, GenericFunc: func(e event.GenericEvent) bool { return false @@ -331,7 +344,7 @@ func (r *BGPPeerReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manag UpdateFunc: func(e event.UpdateEvent) bool { oldVRF := e.ObjectOld.(*v1alpha1.VRF) newVRF := e.ObjectNew.(*v1alpha1.VRF) - return conditions.IsReady(oldVRF) != conditions.IsReady(newVRF) + return conditions.IsConfigured(oldVRF) != conditions.IsConfigured(newVRF) }, GenericFunc: func(e event.GenericEvent) bool { return false @@ -352,6 +365,20 @@ func (r *BGPPeerReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manag }, }), ). + // Watches enqueues BGPPeers when a referenced Interface is created or deleted. + // Only triggers on create and delete events since Interface names are immutable. + Watches( + &v1alpha1.Interface{}, + handler.EnqueueRequestsFromMapFunc(r.interfaceToBGPPeers), + builder.WithPredicates(predicate.Funcs{ + UpdateFunc: func(e event.UpdateEvent) bool { + return false + }, + GenericFunc: func(e event.GenericEvent) bool { + return false + }, + }), + ). Complete(r) } @@ -389,7 +416,7 @@ func (r *BGPPeerReconciler) reconcile(ctx context.Context, s *bgpPeerScope) (ret // BGP has no operational condition, so its ready condition reflects only successful configuration. // Wait for the BGP watch to re-trigger rather than requeuing periodically. - if !conditions.IsReady(bgp) { + if !conditions.IsConfigured(bgp) { conditions.Set(s.BGPPeer, metav1.Condition{ Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, @@ -426,7 +453,7 @@ func (r *BGPPeerReconciler) reconcile(ctx context.Context, s *bgpPeerScope) (ret Reason: v1alpha1.InterfaceNotFoundReason, Message: fmt.Sprintf("source interface %q not found", addr.InterfaceRef.Name), }) - return reconcile.TerminalError(fmt.Errorf("source interface %q not found", addr.InterfaceRef.Name)) + return fmt.Errorf("source interface %q not found", addr.InterfaceRef.Name) } return fmt.Errorf("failed to get source interface %q: %w", addr.InterfaceRef.Name, err) } @@ -639,7 +666,7 @@ func (r *BGPPeerReconciler) reconcileVRF(ctx context.Context, peer *v1alpha1.BGP return nil, reconcile.TerminalError(fmt.Errorf("vrf %s belongs to different device", bgp.Spec.VrfRef.Name)) } - if !conditions.IsReady(vrf) { + if !conditions.IsConfigured(vrf) { // VRF uses ReadyCondition as its top-level configured state (no separate ConfiguredCondition). conditions.Set(peer, metav1.Condition{ Type: v1alpha1.ConfiguredCondition, @@ -885,3 +912,37 @@ func (r *BGPPeerReconciler) routingPolicyToBGPPeers(ctx context.Context, obj cli return requests } + +// interfaceToBGPPeers is a [handler.MapFunc] to be used to enqueue requests for reconciliation +// for BGPPeers when an Interface referenced by their local address is created or deleted. +func (r *BGPPeerReconciler) interfaceToBGPPeers(ctx context.Context, obj client.Object) []ctrl.Request { + intf, ok := obj.(*v1alpha1.Interface) + if !ok { + panic(fmt.Sprintf("Expected an Interface but got a %T", obj)) + } + + log := ctrl.LoggerFrom(ctx, "Interface", klog.KObj(intf)) + + list := new(v1alpha1.BGPPeerList) + if err := r.List( + ctx, list, + client.InNamespace(intf.Namespace), + client.MatchingFields{bgpPeerInterfaceRefIndexKey: intf.Name}, + ); err != nil { + log.Error(err, "Failed to list BGPPeers") + return nil + } + + requests := make([]ctrl.Request, 0, len(list.Items)) + for _, p := range list.Items { + log.V(2).Info("Enqueuing BGPPeer for reconciliation", "BGPPeer", klog.KObj(&p)) + requests = append(requests, ctrl.Request{ + NamespacedName: types.NamespacedName{ + Name: p.Name, + Namespace: p.Namespace, + }, + }) + } + + return requests +} diff --git a/internal/controller/core/bgp_peer_controller_test.go b/internal/controller/core/bgp_peer_controller_test.go index 767ad455e..059192c5e 100644 --- a/internal/controller/core/bgp_peer_controller_test.go +++ b/internal/controller/core/bgp_peer_controller_test.go @@ -34,6 +34,12 @@ var _ = Describe("BGPPeer Controller", func() { }, } Expect(k8sClient.Create(ctx, device)).To(Succeed()) + + By("Waiting for the Device to be created") + Eventually(func(g Gomega) { + resource := &v1alpha1.Device{} + g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(device), resource)).To(Succeed()) + }).Should(Succeed()) }) AfterEach(func() { @@ -93,7 +99,7 @@ var _ = Describe("BGPPeer Controller", func() { Eventually(func(g Gomega) { b := &v1alpha1.BGP{} g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(bgp), b)).To(Succeed()) - g.Expect(conditions.IsReady(b)).To(BeTrue()) + g.Expect(conditions.IsConfigured(b)).To(BeTrue()) }).Should(Succeed()) By("Creating a BGPPeer resource") @@ -250,7 +256,7 @@ var _ = Describe("BGPPeer Controller", func() { Eventually(func(g Gomega) { b := &v1alpha1.BGP{} g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(bgp), b)).To(Succeed()) - g.Expect(conditions.IsReady(b)).To(BeTrue()) + g.Expect(conditions.IsConfigured(b)).To(BeTrue()) }).Should(Succeed()) By("Creating a BGPPeer resource with LocalAddress pointing to a non-existent Interface") @@ -297,6 +303,27 @@ var _ = Describe("BGPPeer Controller", func() { }) It("Should reject local address reference to Interface on different device", func() { + By("Creating a different Device resource for testing") + differentDevice := &v1alpha1.Device{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "different-device-", + Namespace: metav1.NamespaceDefault, + }, + Spec: v1alpha1.DeviceSpec{ + Endpoint: v1alpha1.Endpoint{ + Address: "192.168.10.3:9339", + }, + }, + } + Expect(k8sClient.Create(ctx, differentDevice)).To(Succeed()) + + By("Waiting for the different Device to be in Running phase") + Eventually(func(g Gomega) { + d := &v1alpha1.Device{} + g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(differentDevice), d)).To(Succeed()) + g.Expect(d.Status.Phase).To(Equal(v1alpha1.DevicePhaseRunning)) + }).Should(Succeed()) + By("Creating a BGP resource for the Device") bgp := &v1alpha1.BGP{ ObjectMeta: metav1.ObjectMeta{ @@ -315,7 +342,7 @@ var _ = Describe("BGPPeer Controller", func() { Eventually(func(g Gomega) { b := &v1alpha1.BGP{} g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(bgp), b)).To(Succeed()) - g.Expect(conditions.IsReady(b)).To(BeTrue()) + g.Expect(conditions.IsConfigured(b)).To(BeTrue()) }).Should(Succeed()) By("Creating a Loopback Interface resource on a different device") @@ -325,7 +352,7 @@ var _ = Describe("BGPPeer Controller", func() { Namespace: metav1.NamespaceDefault, }, Spec: v1alpha1.InterfaceSpec{ - DeviceRef: v1alpha1.LocalObjectReference{Name: "different-device"}, + DeviceRef: v1alpha1.LocalObjectReference{Name: differentDevice.Name}, Name: "Loopback0", AdminState: v1alpha1.AdminStateUp, Type: v1alpha1.InterfaceTypeLoopback, @@ -462,7 +489,6 @@ var _ = Describe("BGPPeer Controller", func() { }) It("Should not reconcile iBGP peer if local-as is set", func() { - By("Creating a BGP resource for the Device") By("Creating a BGP resource for the Device") bgp := &v1alpha1.BGP{ ObjectMeta: metav1.ObjectMeta{ @@ -481,7 +507,7 @@ var _ = Describe("BGPPeer Controller", func() { Eventually(func(g Gomega) { b := &v1alpha1.BGP{} g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(bgp), b)).To(Succeed()) - g.Expect(conditions.IsReady(b)).To(BeTrue()) + g.Expect(conditions.IsConfigured(b)).To(BeTrue()) }).Should(Succeed()) By("Creating a BGPPeer resource") diff --git a/internal/controller/core/certificate_controller.go b/internal/controller/core/certificate_controller.go index 640a8c75d..ff88d4257 100644 --- a/internal/controller/core/certificate_controller.go +++ b/internal/controller/core/certificate_controller.go @@ -175,7 +175,7 @@ func (r *CertificateReconciler) Reconcile(ctx context.Context, req ctrl.Request) } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -280,6 +280,10 @@ func (r *CertificateReconciler) reconcile(ctx context.Context, s *certificateSco s.Certificate.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.Certificate) + }() + // Ensure the Certificate is owned by the Device. if !controllerutil.HasControllerReference(s.Certificate) { if err := controllerutil.SetOwnerReference(s.Device, s.Certificate, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -309,8 +313,6 @@ func (r *CertificateReconciler) reconcile(ctx context.Context, s *certificateSco }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.Certificate, cond) return err diff --git a/internal/controller/core/certificate_controller_test.go b/internal/controller/core/certificate_controller_test.go index 501f8f0e5..ad390adbd 100644 --- a/internal/controller/core/certificate_controller_test.go +++ b/internal/controller/core/certificate_controller_test.go @@ -133,11 +133,13 @@ var _ = Describe("Certificate Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.Certificate{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") diff --git a/internal/controller/core/dhcprelay_controller.go b/internal/controller/core/dhcprelay_controller.go index ec88c2a47..7f6e7488c 100644 --- a/internal/controller/core/dhcprelay_controller.go +++ b/internal/controller/core/dhcprelay_controller.go @@ -178,7 +178,7 @@ func (r *DHCPRelayReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -223,6 +223,10 @@ func (r *DHCPRelayReconciler) reconcile(ctx context.Context, s *dhcprelayScope) } s.DHCPRelay.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.DHCPRelay) + }() + // Ensure the DHCPRelay is owned by the Device. if !controllerutil.HasControllerReference(s.DHCPRelay) { if err := controllerutil.SetOwnerReference(s.Device, s.DHCPRelay, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -270,8 +274,6 @@ func (r *DHCPRelayReconciler) reconcile(ctx context.Context, s *dhcprelayScope) }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.DHCPRelay, cond) if err != nil { @@ -536,7 +538,7 @@ func (r *DHCPRelayReconciler) reconcileVRFRef(ctx context.Context, s *dhcprelayS } // Verify the VRF is ready (configured) on the device - if !conditions.IsReady(vrf) { + if !conditions.IsConfigured(vrf) { conditions.Set(s.DHCPRelay, metav1.Condition{ Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, diff --git a/internal/controller/core/dhcprelay_controller_test.go b/internal/controller/core/dhcprelay_controller_test.go index e11406d5c..a7e447221 100644 --- a/internal/controller/core/dhcprelay_controller_test.go +++ b/internal/controller/core/dhcprelay_controller_test.go @@ -16,6 +16,7 @@ import ( "k8s.io/apimachinery/pkg/api/meta" "github.com/ironcore-dev/network-operator/api/core/v1alpha1" + "github.com/ironcore-dev/network-operator/internal/conditions" ) var _ = Describe("DHCPRelay Controller", func() { @@ -191,9 +192,13 @@ var _ = Describe("DHCPRelay Controller", func() { dhcprelay = &v1alpha1.DHCPRelay{} g.Expect(k8sClient.Get(ctx, resourceKey, dhcprelay)).To(Succeed()) - cond := meta.FindStatusCondition(dhcprelay.Status.Conditions, v1alpha1.ReadyCondition) - g.Expect(cond).ToNot(BeNil()) - g.Expect(cond.Status).To(Equal(metav1.ConditionTrue)) + g.Expect(dhcprelay.Status.Conditions).To(HaveLen(3)) + g.Expect(dhcprelay.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) + g.Expect(dhcprelay.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(dhcprelay.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(dhcprelay.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(dhcprelay.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(dhcprelay.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Verifying the status contains configured interface refs") @@ -1122,6 +1127,13 @@ var _ = Describe("DHCPRelay Controller", func() { resourceName = dhcprelay.Name resourceKey = client.ObjectKey{Name: resourceName, Namespace: metav1.NamespaceDefault} + By("Waiting for DHCPRelay's condition to be fully consistent") + Eventually(func(g Gomega) { + resource := &v1alpha1.DHCPRelay{} + g.Expect(k8sClient.Get(ctx, resourceKey, resource)).To(Succeed()) + g.Expect(conditions.IsConfigured(resource)).To(BeFalse()) // checks ObservedGeneration too + }).Should(Succeed()) + By("Verifying DHCPRelay is not ready due to non-configured Interface") Eventually(func(g Gomega) { err := k8sClient.Get(ctx, resourceKey, dhcprelay) @@ -1155,6 +1167,13 @@ var _ = Describe("DHCPRelay Controller", func() { g.Expect(cond.Status).To(Equal(metav1.ConditionTrue)) }).Should(Succeed()) + By("Waiting for Interface's condition to be fully consistent") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, interfaceKey, intf) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(conditions.IsConfigured(intf)).To(BeTrue()) // checks ObservedGeneration too + }).Should(Succeed()) + By("Verifying DHCPRelay becomes ready after Interface is configured (watch triggered re-reconciliation)") Eventually(func(g Gomega) { err := k8sClient.Get(ctx, resourceKey, dhcprelay) diff --git a/internal/controller/core/dns_controller.go b/internal/controller/core/dns_controller.go index 6abe047ad..f93c8e782 100644 --- a/internal/controller/core/dns_controller.go +++ b/internal/controller/core/dns_controller.go @@ -172,7 +172,7 @@ func (r *DNSReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -271,6 +271,10 @@ func (r *DNSReconciler) reconcile(ctx context.Context, s *dnsScope) (reterr erro s.DNS.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.DNS) + }() + // Ensure the DNS is owned by the Device. if !controllerutil.HasControllerReference(s.DNS) { if err := controllerutil.SetOwnerReference(s.Device, s.DNS, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -294,8 +298,6 @@ func (r *DNSReconciler) reconcile(ctx context.Context, s *dnsScope) (reterr erro }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.DNS, cond) return err diff --git a/internal/controller/core/dns_controller_test.go b/internal/controller/core/dns_controller_test.go index 4b5c86c94..e7e833da1 100644 --- a/internal/controller/core/dns_controller_test.go +++ b/internal/controller/core/dns_controller_test.go @@ -104,11 +104,13 @@ var _ = Describe("DNS Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.DNS{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") diff --git a/internal/controller/core/ethernetsegment_controller_test.go b/internal/controller/core/ethernetsegment_controller_test.go index bff49709e..f1ba320b6 100644 --- a/internal/controller/core/ethernetsegment_controller_test.go +++ b/internal/controller/core/ethernetsegment_controller_test.go @@ -11,6 +11,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "github.com/ironcore-dev/network-operator/api/core/v1alpha1" + "github.com/ironcore-dev/network-operator/internal/conditions" ) var _ = Describe("EthernetSegment Controller", func() { @@ -65,6 +66,12 @@ var _ = Describe("EthernetSegment Controller", func() { intf.Namespace = metav1.NamespaceDefault Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, intf))).To(Succeed()) + By("Cleaning up test member Interface resource") + memberIntf := &v1alpha1.Interface{} + memberIntf.Name = name + "-member" + memberIntf.Namespace = metav1.NamespaceDefault + Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, memberIntf))).To(Succeed()) + By("Cleaning up the test Device resource") device := &v1alpha1.Device{} device.Name = name @@ -73,6 +80,21 @@ var _ = Describe("EthernetSegment Controller", func() { }) It("Should successfully reconcile an EthernetSegment", func() { + By("Creating a Physical member Interface") + memberIntf := &v1alpha1.Interface{ + ObjectMeta: metav1.ObjectMeta{ + Name: name + "-member", + Namespace: metav1.NamespaceDefault, + }, + Spec: v1alpha1.InterfaceSpec{ + DeviceRef: v1alpha1.LocalObjectReference{Name: name}, + Name: "eth1", + Type: v1alpha1.InterfaceTypePhysical, + AdminState: v1alpha1.AdminStateUp, + }, + } + Expect(k8sClient.Create(ctx, memberIntf)).To(Succeed()) + By("Creating an Aggregate Interface with switchport config") intf := &v1alpha1.Interface{ ObjectMeta: metav1.ObjectMeta{ @@ -88,13 +110,20 @@ var _ = Describe("EthernetSegment Controller", func() { Mode: v1alpha1.SwitchportModeTrunk, }, Aggregation: &v1alpha1.Aggregation{ - MemberInterfaceRefs: []v1alpha1.LocalObjectReference{{Name: "eth1"}}, + MemberInterfaceRefs: []v1alpha1.LocalObjectReference{{Name: name + "-member"}}, ControlProtocol: v1alpha1.ControlProtocol{Mode: v1alpha1.LACPModeActive}, }, }, } Expect(k8sClient.Create(ctx, intf)).To(Succeed()) + By("Waiting for the Interface to be configured") + Eventually(func(g Gomega) { + i := &v1alpha1.Interface{} + g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(intf), i)).To(Succeed()) + g.Expect(conditions.IsConfigured(i)).To(BeTrue()) + }).Should(Succeed()) + By("Creating an EthernetSegment") es := &v1alpha1.EthernetSegment{ ObjectMeta: metav1.ObjectMeta{ @@ -305,6 +334,21 @@ var _ = Describe("EthernetSegment Controller", func() { }) It("Should handle EthernetSegment referencing Interface without switchport", func() { + By("Creating a Physical member Interface") + memberIntf := &v1alpha1.Interface{ + ObjectMeta: metav1.ObjectMeta{ + Name: name + "-member", + Namespace: metav1.NamespaceDefault, + }, + Spec: v1alpha1.InterfaceSpec{ + DeviceRef: v1alpha1.LocalObjectReference{Name: name}, + Name: "eth1", + Type: v1alpha1.InterfaceTypePhysical, + AdminState: v1alpha1.AdminStateUp, + }, + } + Expect(k8sClient.Create(ctx, memberIntf)).To(Succeed()) + By("Creating an Aggregate Interface without switchport config") intf := &v1alpha1.Interface{ ObjectMeta: metav1.ObjectMeta{ @@ -317,13 +361,20 @@ var _ = Describe("EthernetSegment Controller", func() { Type: v1alpha1.InterfaceTypeAggregate, AdminState: v1alpha1.AdminStateUp, Aggregation: &v1alpha1.Aggregation{ - MemberInterfaceRefs: []v1alpha1.LocalObjectReference{{Name: "eth1"}}, + MemberInterfaceRefs: []v1alpha1.LocalObjectReference{{Name: name + "-member"}}, ControlProtocol: v1alpha1.ControlProtocol{Mode: v1alpha1.LACPModeActive}, }, }, } Expect(k8sClient.Create(ctx, intf)).To(Succeed()) + By("Waiting for the Interface to be configured") + Eventually(func(g Gomega) { + i := &v1alpha1.Interface{} + g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(intf), i)).To(Succeed()) + g.Expect(conditions.IsConfigured(i)).To(BeTrue()) + }).Should(Succeed()) + By("Creating an EthernetSegment referencing the Interface") es := &v1alpha1.EthernetSegment{ ObjectMeta: metav1.ObjectMeta{ @@ -356,6 +407,21 @@ var _ = Describe("EthernetSegment Controller", func() { }).Should(Succeed()) }) It("Should auto-derive ESI when ESIType is MAC and ESI is omitted", func() { + By("Creating a Physical member Interface") + memberIntf := &v1alpha1.Interface{ + ObjectMeta: metav1.ObjectMeta{ + Name: name + "-member", + Namespace: metav1.NamespaceDefault, + }, + Spec: v1alpha1.InterfaceSpec{ + DeviceRef: v1alpha1.LocalObjectReference{Name: name}, + Name: "eth1", + Type: v1alpha1.InterfaceTypePhysical, + AdminState: v1alpha1.AdminStateUp, + }, + } + Expect(k8sClient.Create(ctx, memberIntf)).To(Succeed()) + By("Creating an Aggregate Interface with switchport config") intf := &v1alpha1.Interface{ ObjectMeta: metav1.ObjectMeta{ @@ -371,13 +437,20 @@ var _ = Describe("EthernetSegment Controller", func() { Mode: v1alpha1.SwitchportModeTrunk, }, Aggregation: &v1alpha1.Aggregation{ - MemberInterfaceRefs: []v1alpha1.LocalObjectReference{{Name: "eth1"}}, + MemberInterfaceRefs: []v1alpha1.LocalObjectReference{{Name: name + "-member"}}, ControlProtocol: v1alpha1.ControlProtocol{Mode: v1alpha1.LACPModeActive}, }, }, } Expect(k8sClient.Create(ctx, intf)).To(Succeed()) + By("Waiting for the Interface to be configured") + Eventually(func(g Gomega) { + i := &v1alpha1.Interface{} + g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(intf), i)).To(Succeed()) + g.Expect(conditions.IsConfigured(i)).To(BeTrue()) + }).Should(Succeed()) + By("Creating an EthernetSegment with ESIType MAC and no explicit ESI") es := &v1alpha1.EthernetSegment{ ObjectMeta: metav1.ObjectMeta{ diff --git a/internal/controller/core/evpninstance_controller.go b/internal/controller/core/evpninstance_controller.go index 724c293b4..7e79c22b3 100644 --- a/internal/controller/core/evpninstance_controller.go +++ b/internal/controller/core/evpninstance_controller.go @@ -174,7 +174,7 @@ func (r *EVPNInstanceReconciler) Reconcile(ctx context.Context, req ctrl.Request } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -326,6 +326,10 @@ func (r *EVPNInstanceReconciler) reconcile(ctx context.Context, s *eviScope) (re s.EVPNInstance.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.EVPNInstance) + }() + // Ensure the EVPNInstance is owned by the Device. if !controllerutil.HasControllerReference(s.EVPNInstance) { if err := controllerutil.SetOwnerReference(s.Device, s.EVPNInstance, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -369,8 +373,6 @@ func (r *EVPNInstanceReconciler) reconcile(ctx context.Context, s *eviScope) (re }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.EVPNInstance, cond) return err @@ -388,7 +390,7 @@ func (r *EVPNInstanceReconciler) reconcileVLAN(ctx context.Context, s *eviScope) if err := r.Get(ctx, key, vlan); err != nil { if apierrors.IsNotFound(err) { conditions.Set(s.EVPNInstance, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.VLANNotFoundReason, Message: fmt.Sprintf("referenced VLAN %q not found", key), @@ -400,7 +402,7 @@ func (r *EVPNInstanceReconciler) reconcileVLAN(ctx context.Context, s *eviScope) if vlan.Spec.DeviceRef.Name != s.Device.Name { conditions.Set(s.EVPNInstance, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.CrossDeviceReferenceReason, Message: fmt.Sprintf("referenced VLAN %q does not belong to device %q", vlan.Name, s.Device.Name), @@ -410,7 +412,7 @@ func (r *EVPNInstanceReconciler) reconcileVLAN(ctx context.Context, s *eviScope) if vlan.Status.BridgedBy != nil && vlan.Status.BridgedBy.Name != s.EVPNInstance.Name { conditions.Set(s.EVPNInstance, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.VLANAlreadyInUseReason, Message: fmt.Sprintf("VLAN %q is already in use by EVPNInstance %q", vlan.Name, vlan.Status.BridgedBy.Name), diff --git a/internal/controller/core/evpninstance_controller_test.go b/internal/controller/core/evpninstance_controller_test.go index 1165bc63d..1fce7e4e8 100644 --- a/internal/controller/core/evpninstance_controller_test.go +++ b/internal/controller/core/evpninstance_controller_test.go @@ -130,11 +130,13 @@ var _ = Describe("EVPNInstance Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.EVPNInstance{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Verifying the VLAN is labeled with L2VNI label") @@ -186,12 +188,14 @@ var _ = Describe("EVPNInstance Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.EVPNInstance{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionFalse)) - g.Expect(resource.Status.Conditions[0].Reason).To(Equal(v1alpha1.VLANNotFoundReason)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Reason).To(Equal(v1alpha1.VLANNotFoundReason)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) }) @@ -238,12 +242,14 @@ var _ = Describe("EVPNInstance Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.EVPNInstance{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionFalse)) - g.Expect(resource.Status.Conditions[0].Reason).To(Equal(v1alpha1.CrossDeviceReferenceReason)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Reason).To(Equal(v1alpha1.CrossDeviceReferenceReason)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) }) }) diff --git a/internal/controller/core/isis_controller.go b/internal/controller/core/isis_controller.go index 00c77033b..d88a3b56f 100644 --- a/internal/controller/core/isis_controller.go +++ b/internal/controller/core/isis_controller.go @@ -173,7 +173,7 @@ func (r *ISISReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -290,6 +290,10 @@ func (r *ISISReconciler) reconcile(ctx context.Context, s *isisScope) (reterr er s.ISIS.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.ISIS) + }() + // Ensure the ISIS is owned by the Device. if !controllerutil.HasControllerReference(s.ISIS) { if err := controllerutil.SetOwnerReference(s.Device, s.ISIS, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -297,10 +301,6 @@ func (r *ISISReconciler) reconcile(ctx context.Context, s *isisScope) (reterr er } } - defer func() { - conditions.RecomputeReady(s.ISIS) - }() - var interfaces []*v1alpha1.Interface for _, iface := range s.ISIS.Spec.InterfaceRefs { intf := new(v1alpha1.Interface) @@ -347,8 +347,6 @@ func (r *ISISReconciler) reconcile(ctx context.Context, s *isisScope) (reterr er }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.ISIS, cond) return err diff --git a/internal/controller/core/isis_controller_test.go b/internal/controller/core/isis_controller_test.go index f6d635ac1..c8a5cd831 100644 --- a/internal/controller/core/isis_controller_test.go +++ b/internal/controller/core/isis_controller_test.go @@ -105,11 +105,13 @@ var _ = Describe("ISIS Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.ISIS{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") diff --git a/internal/controller/core/lldp_controller.go b/internal/controller/core/lldp_controller.go index 4a4471b45..9fab42a8b 100644 --- a/internal/controller/core/lldp_controller.go +++ b/internal/controller/core/lldp_controller.go @@ -165,7 +165,7 @@ func (r *LLDPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } diff --git a/internal/controller/core/managementaccess_controller.go b/internal/controller/core/managementaccess_controller.go index 1cd63f6d2..5fdcbc7c5 100644 --- a/internal/controller/core/managementaccess_controller.go +++ b/internal/controller/core/managementaccess_controller.go @@ -172,7 +172,7 @@ func (r *ManagementAccessReconciler) Reconcile(ctx context.Context, req ctrl.Req } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -271,6 +271,10 @@ func (r *ManagementAccessReconciler) reconcile(ctx context.Context, s *managemen s.ManagementAccess.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.ManagementAccess) + }() + // Ensure the ManagementAccess is owned by the Device. if !controllerutil.HasControllerReference(s.ManagementAccess) { if err := controllerutil.SetOwnerReference(s.Device, s.ManagementAccess, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -294,8 +298,6 @@ func (r *ManagementAccessReconciler) reconcile(ctx context.Context, s *managemen }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.ManagementAccess, cond) return err diff --git a/internal/controller/core/managementaccess_controller_test.go b/internal/controller/core/managementaccess_controller_test.go index d5b10b730..478acd9e3 100644 --- a/internal/controller/core/managementaccess_controller_test.go +++ b/internal/controller/core/managementaccess_controller_test.go @@ -102,11 +102,13 @@ var _ = Describe("ManagementAccess Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.ManagementAccess{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") diff --git a/internal/controller/core/ntp_controller.go b/internal/controller/core/ntp_controller.go index 806799a50..6a1988b33 100644 --- a/internal/controller/core/ntp_controller.go +++ b/internal/controller/core/ntp_controller.go @@ -172,7 +172,7 @@ func (r *NTPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -271,6 +271,10 @@ func (r *NTPReconciler) reconcile(ctx context.Context, s *ntpScope) (reterr erro s.NTP.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.NTP) + }() + // Ensure the NTP is owned by the Device. if !controllerutil.HasControllerReference(s.NTP) { if err := controllerutil.SetOwnerReference(s.Device, s.NTP, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -294,8 +298,6 @@ func (r *NTPReconciler) reconcile(ctx context.Context, s *ntpScope) (reterr erro }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.NTP, cond) return err diff --git a/internal/controller/core/ntp_controller_test.go b/internal/controller/core/ntp_controller_test.go index 972e9c75b..f248675fc 100644 --- a/internal/controller/core/ntp_controller_test.go +++ b/internal/controller/core/ntp_controller_test.go @@ -105,11 +105,13 @@ var _ = Describe("NTP Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.NTP{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") diff --git a/internal/controller/core/nve_controller.go b/internal/controller/core/nve_controller.go index bb032f748..0a7feb878 100644 --- a/internal/controller/core/nve_controller.go +++ b/internal/controller/core/nve_controller.go @@ -173,7 +173,7 @@ func (r *NetworkVirtualizationEdgeReconciler) Reconcile(ctx context.Context, req } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } diff --git a/internal/controller/core/pim_controller.go b/internal/controller/core/pim_controller.go index 5bd8d03ea..e2eab9087 100644 --- a/internal/controller/core/pim_controller.go +++ b/internal/controller/core/pim_controller.go @@ -173,7 +173,7 @@ func (r *PIMReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -290,6 +290,10 @@ func (r *PIMReconciler) reconcile(ctx context.Context, s *pimScope) (reterr erro s.PIM.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.PIM) + }() + // Ensure the PIM is owned by the Device. if !controllerutil.HasControllerReference(s.PIM) { if err := controllerutil.SetOwnerReference(s.Device, s.PIM, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -303,7 +307,7 @@ func (r *PIMReconciler) reconcile(ctx context.Context, s *pimScope) (reterr erro if err := r.Get(ctx, client.ObjectKey{Name: intf.Name, Namespace: s.PIM.Namespace}, res); err != nil { if apierrors.IsNotFound(err) { conditions.Set(s.PIM, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.InterfaceNotFoundReason, Message: fmt.Sprintf("interface %q not found", intf.Name), @@ -315,7 +319,7 @@ func (r *PIMReconciler) reconcile(ctx context.Context, s *pimScope) (reterr erro if !conditions.IsConfigured(res) { conditions.Set(s.PIM, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.WaitingForDependenciesReason, Message: "Waiting for referenced interfaces to become configured", @@ -346,8 +350,6 @@ func (r *PIMReconciler) reconcile(ctx context.Context, s *pimScope) (reterr erro }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.PIM, cond) return err diff --git a/internal/controller/core/pim_controller_test.go b/internal/controller/core/pim_controller_test.go index 427e58d41..0e30865c9 100644 --- a/internal/controller/core/pim_controller_test.go +++ b/internal/controller/core/pim_controller_test.go @@ -98,11 +98,13 @@ var _ = Describe("PIM Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.PIM{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") @@ -150,7 +152,7 @@ var _ = Describe("PIM Controller", func() { Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, device))).To(Succeed()) }) - It("Should set ReadyCondition to false when interfaceRef does not exist", func() { + It("Should set ConfiguredCondition to false when interfaceRef does not exist", func() { By("Creating a PIM resource with a non-existent interfaceRef") pim := &v1alpha1.PIM{ ObjectMeta: metav1.ObjectMeta{ @@ -169,12 +171,12 @@ var _ = Describe("PIM Controller", func() { } Expect(k8sClient.Create(ctx, pim)).To(Succeed()) - By("Verifying the controller sets ReadyCondition to false") + By("Verifying the controller sets ConfiguredCondition to false") Eventually(func(g Gomega) { resource := &v1alpha1.PIM{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - ready := meta.FindStatusCondition(resource.Status.Conditions, v1alpha1.ReadyCondition) + ready := meta.FindStatusCondition(resource.Status.Conditions, v1alpha1.ConfiguredCondition) g.Expect(ready).NotTo(BeNil()) g.Expect(ready.Status).To(Equal(metav1.ConditionFalse)) g.Expect(ready.Reason).To(Equal(v1alpha1.InterfaceNotFoundReason)) diff --git a/internal/controller/core/prefixset_controller.go b/internal/controller/core/prefixset_controller.go index 73a220631..60357971a 100644 --- a/internal/controller/core/prefixset_controller.go +++ b/internal/controller/core/prefixset_controller.go @@ -172,7 +172,7 @@ func (r *PrefixSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -271,6 +271,10 @@ func (r *PrefixSetReconciler) reconcile(ctx context.Context, s *prefixSetScope) s.PrefixSet.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.PrefixSet) + }() + // Ensure the PrefixSet is owned by the Device. if !controllerutil.HasControllerReference(s.PrefixSet) { if err := controllerutil.SetOwnerReference(s.Device, s.PrefixSet, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -300,8 +304,6 @@ func (r *PrefixSetReconciler) reconcile(ctx context.Context, s *prefixSetScope) }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.PrefixSet, cond) return err diff --git a/internal/controller/core/prefixset_controller_test.go b/internal/controller/core/prefixset_controller_test.go index 540a886ff..f7089ff2b 100644 --- a/internal/controller/core/prefixset_controller_test.go +++ b/internal/controller/core/prefixset_controller_test.go @@ -109,11 +109,13 @@ var _ = Describe("PrefixSet Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.PrefixSet{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") diff --git a/internal/controller/core/routingpolicy_controller.go b/internal/controller/core/routingpolicy_controller.go index 63acc8c37..7a982023f 100644 --- a/internal/controller/core/routingpolicy_controller.go +++ b/internal/controller/core/routingpolicy_controller.go @@ -172,7 +172,7 @@ func (r *RoutingPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Reques } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -300,6 +300,10 @@ func (r *RoutingPolicyReconciler) reconcile(ctx context.Context, s *routingPolic s.RoutingPolicy.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.RoutingPolicy) + }() + // Ensure the RoutingPolicy is owned by the Device. if !controllerutil.HasControllerReference(s.RoutingPolicy) { if err := controllerutil.SetOwnerReference(s.Device, s.RoutingPolicy, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -335,8 +339,6 @@ func (r *RoutingPolicyReconciler) reconcile(ctx context.Context, s *routingPolic }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.RoutingPolicy, cond) return err @@ -378,7 +380,7 @@ func (r *RoutingPolicyReconciler) reconcilePrefixSet(ctx context.Context, s *rou if err := r.Get(ctx, key, prefixSet); err != nil { if apierrors.IsNotFound(err) { conditions.Set(s.RoutingPolicy, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.PrefixSetNotFoundReason, Message: fmt.Sprintf("referenced PrefixSet %q not found", key), @@ -390,7 +392,7 @@ func (r *RoutingPolicyReconciler) reconcilePrefixSet(ctx context.Context, s *rou if prefixSet.Spec.DeviceRef.Name != s.Device.Name { conditions.Set(s.RoutingPolicy, metav1.Condition{ - Type: v1alpha1.ReadyCondition, + Type: v1alpha1.ConfiguredCondition, Status: metav1.ConditionFalse, Reason: v1alpha1.CrossDeviceReferenceReason, Message: fmt.Sprintf("referenced PrefixSet %q does not belong to device %q", prefixSet.Name, s.Device.Name), diff --git a/internal/controller/core/routingpolicy_controller_test.go b/internal/controller/core/routingpolicy_controller_test.go index d9579f6da..f2c791cbc 100644 --- a/internal/controller/core/routingpolicy_controller_test.go +++ b/internal/controller/core/routingpolicy_controller_test.go @@ -14,6 +14,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "github.com/ironcore-dev/network-operator/api/core/v1alpha1" + "github.com/ironcore-dev/network-operator/internal/conditions" ) var _ = Describe("RoutingPolicy Controller", func() { @@ -114,11 +115,13 @@ var _ = Describe("RoutingPolicy Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.RoutingPolicy{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") @@ -181,15 +184,24 @@ var _ = Describe("RoutingPolicy Controller", func() { } Expect(k8sClient.Create(ctx, rp)).To(Succeed()) + By("Waiting for RoutingPolicy's condition to be fully consistent") + Eventually(func(g Gomega) { + resource := &v1alpha1.RoutingPolicy{} + g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) + g.Expect(conditions.IsConfigured(resource)).To(BeFalse()) // checks ObservedGeneration too + }).Should(Succeed()) + By("Verifying the controller sets successful status conditions") Eventually(func(g Gomega) { resource := &v1alpha1.RoutingPolicy{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Verifying the RoutingPolicy is configured in the provider") @@ -229,12 +241,14 @@ var _ = Describe("RoutingPolicy Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.RoutingPolicy{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionFalse)) - g.Expect(resource.Status.Conditions[0].Reason).To(Equal(v1alpha1.PrefixSetNotFoundReason)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Reason).To(Equal(v1alpha1.PrefixSetNotFoundReason)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) }) @@ -334,11 +348,13 @@ var _ = Describe("RoutingPolicy Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.RoutingPolicy{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Verifying the RoutingPolicy is configured in the provider") @@ -397,12 +413,14 @@ var _ = Describe("RoutingPolicy Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.RoutingPolicy{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionFalse)) - g.Expect(resource.Status.Conditions[0].Reason).To(Equal(v1alpha1.CrossDeviceReferenceReason)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Reason).To(Equal(v1alpha1.CrossDeviceReferenceReason)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) }) }) diff --git a/internal/controller/core/snmp_controller.go b/internal/controller/core/snmp_controller.go index 2c2012e62..e753aa782 100644 --- a/internal/controller/core/snmp_controller.go +++ b/internal/controller/core/snmp_controller.go @@ -172,7 +172,7 @@ func (r *SNMPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -271,6 +271,10 @@ func (r *SNMPReconciler) reconcile(ctx context.Context, s *snmpScope) (reterr er s.SNMP.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.SNMP) + }() + // Ensure the SNMP is owned by the Device. if !controllerutil.HasControllerReference(s.SNMP) { if err := controllerutil.SetOwnerReference(s.Device, s.SNMP, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -294,8 +298,6 @@ func (r *SNMPReconciler) reconcile(ctx context.Context, s *snmpScope) (reterr er }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.SNMP, cond) return err diff --git a/internal/controller/core/snmp_controller_test.go b/internal/controller/core/snmp_controller_test.go index 145dfee47..31d39af37 100644 --- a/internal/controller/core/snmp_controller_test.go +++ b/internal/controller/core/snmp_controller_test.go @@ -116,11 +116,13 @@ var _ = Describe("SNMP Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.SNMP{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") diff --git a/internal/controller/core/suite_test.go b/internal/controller/core/suite_test.go index 67e774cc9..55c78977d 100644 --- a/internal/controller/core/suite_test.go +++ b/internal/controller/core/suite_test.go @@ -90,9 +90,10 @@ var _ = BeforeSuite(func() { Expect(cfg).NotTo(BeNil()) k8sManager, err = ctrl.NewManager(cfg, ctrl.Options{ - Scheme: scheme.Scheme, - Logger: GinkgoLogr, - Metrics: metricsserver.Options{BindAddress: "0"}, + Scheme: scheme.Scheme, + Logger: GinkgoLogr, + Metrics: metricsserver.Options{BindAddress: "0"}, + HealthProbeBindAddress: "0", // This enables running multiple instances of the test suite in parallel }) Expect(err).ToNot(HaveOccurred()) diff --git a/internal/controller/core/syslog_controller.go b/internal/controller/core/syslog_controller.go index 12d8dd364..edf864d9d 100644 --- a/internal/controller/core/syslog_controller.go +++ b/internal/controller/core/syslog_controller.go @@ -172,7 +172,7 @@ func (r *SyslogReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ c } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -271,6 +271,10 @@ func (r *SyslogReconciler) reconcile(ctx context.Context, s *syslogScope) (reter s.Syslog.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.Syslog) + }() + // Ensure the Syslog is owned by the Device. if !controllerutil.HasControllerReference(s.Syslog) { if err := controllerutil.SetOwnerReference(s.Device, s.Syslog, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -300,8 +304,6 @@ func (r *SyslogReconciler) reconcile(ctx context.Context, s *syslogScope) (reter }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.Syslog, cond) return err diff --git a/internal/controller/core/syslog_controller_test.go b/internal/controller/core/syslog_controller_test.go index 8e477ca06..4a2e38b02 100644 --- a/internal/controller/core/syslog_controller_test.go +++ b/internal/controller/core/syslog_controller_test.go @@ -111,11 +111,13 @@ var _ = Describe("Syslog Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.Syslog{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") diff --git a/internal/controller/core/user_controller.go b/internal/controller/core/user_controller.go index ff16800a3..7ac85b211 100644 --- a/internal/controller/core/user_controller.go +++ b/internal/controller/core/user_controller.go @@ -175,7 +175,7 @@ func (r *UserReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -280,6 +280,10 @@ func (r *UserReconciler) reconcile(ctx context.Context, s *userScope) (reterr er s.User.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.User) + }() + // Ensure the User is owned by the Device. if !controllerutil.HasControllerReference(s.User) { if err := controllerutil.SetOwnerReference(s.Device, s.User, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -326,8 +330,6 @@ func (r *UserReconciler) reconcile(ctx context.Context, s *userScope) (reterr er }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.User, cond) return err diff --git a/internal/controller/core/user_controller_test.go b/internal/controller/core/user_controller_test.go index 94cf845e6..1492eb2f3 100644 --- a/internal/controller/core/user_controller_test.go +++ b/internal/controller/core/user_controller_test.go @@ -121,11 +121,13 @@ var _ = Describe("User Controller", func() { Eventually(func(g Gomega) { resource := &v1alpha1.User{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) - g.Expect(resource.Status.Conditions).To(HaveLen(2)) + g.Expect(resource.Status.Conditions).To(HaveLen(3)) g.Expect(resource.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(resource.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(resource.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(resource.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(resource.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(resource.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the resource is created in the provider") diff --git a/internal/controller/core/vlan_controller_test.go b/internal/controller/core/vlan_controller_test.go index edc1b8cd5..6600be88a 100644 --- a/internal/controller/core/vlan_controller_test.go +++ b/internal/controller/core/vlan_controller_test.go @@ -11,6 +11,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "github.com/ironcore-dev/network-operator/api/core/v1alpha1" + "github.com/ironcore-dev/network-operator/internal/conditions" ) var _ = Describe("VLAN Controller", func() { @@ -97,6 +98,13 @@ var _ = Describe("VLAN Controller", func() { g.Expect(resource.OwnerReferences[0].Name).To(Equal(name)) }).Should(Succeed()) + By("Waiting for VLAN's condition to be fully consistent") + Eventually(func(g Gomega) { + resource := &v1alpha1.VLAN{} + g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) + g.Expect(conditions.IsConfigured(resource)).To(BeTrue()) // checks ObservedGeneration too + }).Should(Succeed()) + By("Updating the resource status") Eventually(func(g Gomega) { resource := &v1alpha1.VLAN{} diff --git a/internal/controller/core/vrf_controller.go b/internal/controller/core/vrf_controller.go index 05a1cb30a..163d0e689 100644 --- a/internal/controller/core/vrf_controller.go +++ b/internal/controller/core/vrf_controller.go @@ -174,7 +174,7 @@ func (r *VRFReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl } orig := obj.DeepCopy() - if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition) { + if conditions.InitializeConditions(obj, v1alpha1.ReadyCondition, v1alpha1.ConfiguredCondition) { log.V(1).Info("Initializing status conditions") return ctrl.Result{}, r.Status().Update(ctx, obj) } @@ -219,6 +219,10 @@ func (r *VRFReconciler) reconcile(ctx context.Context, s *vrfScope) (reterr erro } s.VRF.Labels[v1alpha1.DeviceLabel] = s.Device.Name + defer func() { + conditions.RecomputeReady(s.VRF) + }() + // Ensure the VRF is owned by the Device. if !controllerutil.HasControllerReference(s.VRF) { if err := controllerutil.SetOwnerReference(s.Device, s.VRF, r.Scheme, controllerutil.WithBlockOwnerDeletion(true)); err != nil { @@ -243,8 +247,6 @@ func (r *VRFReconciler) reconcile(ctx context.Context, s *vrfScope) (reterr erro }) cond := conditions.FromError(err) - // As this resource is configuration only, we use the Configured condition as top-level Ready condition. - cond.Type = v1alpha1.ReadyCondition conditions.Set(s.VRF, cond) return err diff --git a/internal/controller/core/vrf_controller_test.go b/internal/controller/core/vrf_controller_test.go index e9d76ff51..caa4d1eb1 100644 --- a/internal/controller/core/vrf_controller_test.go +++ b/internal/controller/core/vrf_controller_test.go @@ -115,11 +115,13 @@ var _ = Describe("VRF Controller", func() { By("Updating the resource status") Eventually(func(g Gomega) { g.Expect(k8sClient.Get(ctx, key, vrf)).To(Succeed()) - g.Expect(vrf.Status.Conditions).To(HaveLen(2)) + g.Expect(vrf.Status.Conditions).To(HaveLen(3)) g.Expect(vrf.Status.Conditions[0].Type).To(Equal(v1alpha1.ReadyCondition)) g.Expect(vrf.Status.Conditions[0].Status).To(Equal(metav1.ConditionTrue)) - g.Expect(vrf.Status.Conditions[1].Type).To(Equal(v1alpha1.PausedCondition)) - g.Expect(vrf.Status.Conditions[1].Status).To(Equal(metav1.ConditionFalse)) + g.Expect(vrf.Status.Conditions[1].Type).To(Equal(v1alpha1.ConfiguredCondition)) + g.Expect(vrf.Status.Conditions[1].Status).To(Equal(metav1.ConditionTrue)) + g.Expect(vrf.Status.Conditions[2].Type).To(Equal(v1alpha1.PausedCondition)) + g.Expect(vrf.Status.Conditions[2].Status).To(Equal(metav1.ConditionFalse)) }).Should(Succeed()) By("Ensuring the VRF is created in the provider")