@@ -25,13 +25,18 @@ import (
2525 policyv1 "k8s.io/api/policy/v1"
2626 apiextensionshelpers "k8s.io/apiextensions-apiserver/pkg/apihelpers"
2727 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
28+ "k8s.io/apimachinery/pkg/api/meta"
2829 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2930 "k8s.io/apimachinery/pkg/runtime"
3031 "k8s.io/apimachinery/pkg/runtime/schema"
3132 "k8s.io/component-helpers/apps/poddisruptionbudget"
3233 "k8s.io/klog/v2"
3334
35+ fleetnetworkingv1alpha1 "go.goms.io/fleet-networking/api/v1alpha1"
36+ "go.goms.io/fleet-networking/pkg/common/objectmeta"
37+
3438 "go.goms.io/fleet/pkg/utils"
39+ "go.goms.io/fleet/pkg/utils/condition"
3540 "go.goms.io/fleet/pkg/utils/controller"
3641)
3742
@@ -104,6 +109,8 @@ func trackInMemberClusterObjAvailabilityByGVR(
104109 return trackCRDAvailability (inMemberClusterObj )
105110 case utils .PodDisruptionBudgetGVR :
106111 return trackPDBAvailability (inMemberClusterObj )
112+ case utils .ServiceExportGVR :
113+ return trackServiceExportAvailability (inMemberClusterObj )
107114 default :
108115 if isDataResource (* gvr ) {
109116 klog .V (2 ).InfoS ("The object from the member cluster is a data object, consider it to be immediately available" ,
@@ -268,6 +275,44 @@ func trackPDBAvailability(curObj *unstructured.Unstructured) (ManifestProcessing
268275 return ManifestProcessingAvailabilityResultTypeNotYetAvailable , nil
269276}
270277
278+ // trackServiceExportAvailability tracks the availability of a service export in the member cluster.
279+ // It is available if the ServiceExportValid condition is true (will be false if annotation value is invalid).
280+ // If the weight is not 0, ServiceExportValid condition must be true and the ServiceExportConflict condition must be false.
281+ func trackServiceExportAvailability (curObj * unstructured.Unstructured ) (ManifestProcessingAvailabilityResultType , error ) {
282+ var svcExport fleetnetworkingv1alpha1.ServiceExport
283+ if err := runtime .DefaultUnstructuredConverter .FromUnstructured (curObj .Object , & svcExport ); err != nil {
284+ return ManifestProcessingAvailabilityResultTypeFailed , controller .NewUnexpectedBehaviorError (err )
285+ }
286+
287+ // Check if ServiceExport is valid and up to date
288+ svcExportObj := klog .KObj (curObj )
289+ validCond := meta .FindStatusCondition (svcExport .Status .Conditions , string (fleetnetworkingv1alpha1 .ServiceExportValid ))
290+ if ! condition .IsConditionStatusTrue (validCond , svcExport .Generation ) {
291+ klog .V (2 ).InfoS ("Still need to wait for ServiceExport to be valid" , "serviceExport" , svcExportObj , "validCondition" , validCond )
292+ return ManifestProcessingAvailabilityResultTypeNotYetAvailable , nil
293+ }
294+ // Validate annotation weight. Updating the annotation won't change the object generation,
295+ // so the current status is not reliable and need to validate the annotation again here
296+ weight , err := objectmeta .ExtractWeightFromServiceExport (& svcExport )
297+ if err != nil {
298+ klog .Errorf (err .Error (), "ServiceExport has invalid weight" , "serviceExport" , svcExportObj )
299+ return ManifestProcessingAvailabilityResultTypeNotYetAvailable , err
300+ }
301+ if weight != 0 {
302+ // Check conflict condition for non-zero weight
303+ conflictCond := meta .FindStatusCondition (svcExport .Status .Conditions , string (fleetnetworkingv1alpha1 .ServiceExportConflict ))
304+ if ! condition .IsConditionStatusFalse (conflictCond , svcExport .Generation ) {
305+ klog .V (2 ).InfoS ("Still need to wait for ServiceExport to not have conflicts" , "serviceExport" , svcExportObj , "conflictCondition" , conflictCond )
306+ return ManifestProcessingAvailabilityResultTypeNotYetAvailable , nil
307+ }
308+ } else {
309+ klog .V (2 ).InfoS ("Skipping checking the conflict condition for the weight 0" , "serviceExport" , svcExportObj )
310+ }
311+
312+ klog .V (2 ).InfoS ("ServiceExport is available" , "serviceExport" , svcExportObj )
313+ return ManifestProcessingAvailabilityResultTypeAvailable , nil
314+ }
315+
271316// isDataResource checks if the resource is a data resource; such resources are
272317// available immediately after creation.
273318func isDataResource (gvr schema.GroupVersionResource ) bool {
0 commit comments