Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ require (
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.10.0
github.com/wI2L/jsondiff v0.6.0
go.goms.io/fleet-networking v0.3.5
go.goms.io/fleet-networking v0.3.3
Comment thread
zhiying-lin marked this conversation as resolved.
go.uber.org/atomic v1.11.0
go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,8 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.goms.io/fleet-networking v0.3.5 h1:nR0LFEbpu9cfBwYFVV8cGB8OARemIwtzaaFpRpp1GtQ=
go.goms.io/fleet-networking v0.3.5/go.mod h1:zegH1iEZScjUWiGnXL67D/ZfWTM9DBUaSo1gPWaxLek=
go.goms.io/fleet-networking v0.3.3 h1:5rwBntaUoLF+E1CzaWAEL4GdvLJPQorKhjgkbLlllPE=
go.goms.io/fleet-networking v0.3.3/go.mod h1:Qgbi8M1fGaz/p5rtb6HJPmTDATWRnMt9HD1gz57WKUc=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
Expand Down
45 changes: 0 additions & 45 deletions pkg/controllers/workapplier/availability_tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,13 @@ import (
policyv1 "k8s.io/api/policy/v1"
apiextensionshelpers "k8s.io/apiextensions-apiserver/pkg/apihelpers"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/component-helpers/apps/poddisruptionbudget"
"k8s.io/klog/v2"

fleetnetworkingv1alpha1 "go.goms.io/fleet-networking/api/v1alpha1"
"go.goms.io/fleet-networking/pkg/common/objectmeta"

"go.goms.io/fleet/pkg/utils"
"go.goms.io/fleet/pkg/utils/condition"
"go.goms.io/fleet/pkg/utils/controller"
)

Expand Down Expand Up @@ -88,8 +83,6 @@ func trackInMemberClusterObjAvailabilityByGVR(
return trackCRDAvailability(inMemberClusterObj)
case utils.PodDisruptionBudgetGVR:
return trackPDBAvailability(inMemberClusterObj)
case utils.ServiceExportGVR:
return trackServiceExportAvailability(inMemberClusterObj)
default:
if isDataResource(*gvr) {
klog.V(2).InfoS("The object from the member cluster is a data object, consider it to be immediately available",
Expand Down Expand Up @@ -254,44 +247,6 @@ func trackPDBAvailability(curObj *unstructured.Unstructured) (ManifestProcessing
return ManifestProcessingAvailabilityResultTypeNotYetAvailable, nil
}

// trackServiceExportAvailability tracks the availability of a service export in the member cluster.
// It is available if the ServiceExportValid condition is true (will be false if annotation value is invalid).
// If the weight is not 0, ServiceExportValid condition must be true and the ServiceExportConflict condition must be false.
func trackServiceExportAvailability(curObj *unstructured.Unstructured) (ManifestProcessingAvailabilityResultType, error) {
var svcExport fleetnetworkingv1alpha1.ServiceExport
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(curObj.Object, &svcExport); err != nil {
return ManifestProcessingAvailabilityResultTypeFailed, controller.NewUnexpectedBehaviorError(err)
}

// Check if ServiceExport is valid and up to date
svcExportObj := klog.KObj(curObj)
validCond := meta.FindStatusCondition(svcExport.Status.Conditions, string(fleetnetworkingv1alpha1.ServiceExportValid))
if !condition.IsConditionStatusTrue(validCond, svcExport.Generation) {
klog.V(2).InfoS("Still need to wait for ServiceExport to be valid", "serviceExport", svcExportObj, "validCondition", validCond)
return ManifestProcessingAvailabilityResultTypeNotYetAvailable, nil
}
// Validate annotation weight. Updating the annotation won't change the object generation,
// so the current status is not reliable and need to validate the annotation again here.
weight, err := objectmeta.ExtractWeightFromServiceExport(&svcExport)
if err != nil {
klog.Error(err, "ServiceExport has invalid weight", "serviceExport", svcExportObj)
return ManifestProcessingAvailabilityResultTypeNotYetAvailable, nil
}
if weight != 0 {
// Check conflict condition for non-zero weight
conflictCond := meta.FindStatusCondition(svcExport.Status.Conditions, string(fleetnetworkingv1alpha1.ServiceExportConflict))
if !condition.IsConditionStatusFalse(conflictCond, svcExport.Generation) {
klog.V(2).InfoS("Still need to wait for ServiceExport to not have conflicts", "serviceExport", svcExportObj, "conflictCondition", conflictCond)
return ManifestProcessingAvailabilityResultTypeNotYetAvailable, nil
}
} else {
klog.V(2).InfoS("Skipping checking the conflict condition for the weight 0", "serviceExport", svcExportObj)
}

klog.V(2).InfoS("ServiceExport is available", "serviceExport", svcExportObj)
return ManifestProcessingAvailabilityResultTypeAvailable, nil
}

// isDataResource checks if the resource is a data resource; such resources are
// available immediately after creation.
func isDataResource(gvr schema.GroupVersionResource) bool {
Expand Down
287 changes: 0 additions & 287 deletions pkg/controllers/workapplier/availability_tracker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ import (
"k8s.io/klog/v2"
"k8s.io/utils/ptr"

fleetnetworkingv1alpha1 "go.goms.io/fleet-networking/api/v1alpha1"
"go.goms.io/fleet-networking/pkg/common/objectmeta"

fleetv1beta1 "go.goms.io/fleet/apis/placement/v1beta1"
"go.goms.io/fleet/pkg/utils"
"go.goms.io/fleet/pkg/utils/parallelizer"
Expand Down Expand Up @@ -986,290 +983,6 @@ func TestTrackInMemberClusterObjAvailabilityByGVR(t *testing.T) {
}
}

func TestServiceExportAvailability(t *testing.T) {
svcExportTemplate := &fleetnetworkingv1alpha1.ServiceExport{
ObjectMeta: metav1.ObjectMeta{
Name: "test-svcExport",
Namespace: nsName,
Annotations: map[string]string{},
Generation: 3,
},
}

testCases := []struct {
name string
weight string
status fleetnetworkingv1alpha1.ServiceExportStatus
wantManifestProcessingAvailabilityResultType ManifestProcessingAvailabilityResultType
}{
{
name: "available svcExport (annotation weight is 0)",
weight: "0",
status: fleetnetworkingv1alpha1.ServiceExportStatus{
Conditions: []metav1.Condition{
{
Type: string(fleetnetworkingv1alpha1.ServiceExportValid),
Status: metav1.ConditionTrue,
Reason: "ServiceIsValid",
ObservedGeneration: 3,
},
},
},
wantManifestProcessingAvailabilityResultType: ManifestProcessingAvailabilityResultTypeAvailable,
},
{
name: "unavailable svcExport (ServiceExportValid is false)",
weight: "0",
status: fleetnetworkingv1alpha1.ServiceExportStatus{
Conditions: []metav1.Condition{
{
Type: string(fleetnetworkingv1alpha1.ServiceExportValid),
Status: metav1.ConditionFalse,
Reason: "ServiceNotFound",
ObservedGeneration: 3,
},
},
},
wantManifestProcessingAvailabilityResultType: ManifestProcessingAvailabilityResultTypeNotYetAvailable,
},
{
name: "unavailable svcExport (different generation, annotation weight is 0)",
weight: "0",
status: fleetnetworkingv1alpha1.ServiceExportStatus{
Conditions: []metav1.Condition{
{
Type: string(fleetnetworkingv1alpha1.ServiceExportValid),
Status: metav1.ConditionTrue,
Reason: "ServiceIsValid",
ObservedGeneration: 2,
},
},
},
wantManifestProcessingAvailabilityResultType: ManifestProcessingAvailabilityResultTypeNotYetAvailable,
},
{
name: "available svcExport with no conflict (annotation weight is 1)",
weight: "1",
status: fleetnetworkingv1alpha1.ServiceExportStatus{
Conditions: []metav1.Condition{
{
Type: string(fleetnetworkingv1alpha1.ServiceExportValid),
Status: metav1.ConditionTrue,
Reason: "ServiceIsValid",
ObservedGeneration: 3,
},
{
Type: string(fleetnetworkingv1alpha1.ServiceExportConflict),
Status: metav1.ConditionFalse,
Reason: "NoConflictFound",
ObservedGeneration: 3,
},
},
},
wantManifestProcessingAvailabilityResultType: ManifestProcessingAvailabilityResultTypeAvailable,
},
{
name: "unavailable svcExport with conflict (annotation weight is 1)",
weight: "1",
status: fleetnetworkingv1alpha1.ServiceExportStatus{
Conditions: []metav1.Condition{
{
Type: string(fleetnetworkingv1alpha1.ServiceExportValid),
Status: metav1.ConditionTrue,
Reason: "ServiceIsValid",
ObservedGeneration: 3,
},
{
Type: string(fleetnetworkingv1alpha1.ServiceExportConflict),
Status: metav1.ConditionTrue,
Reason: "ConflictFound",
ObservedGeneration: 3,
},
},
},
wantManifestProcessingAvailabilityResultType: ManifestProcessingAvailabilityResultTypeNotYetAvailable,
},
{
name: "unavailable invalid svcExport (annotation weight is 1)",
weight: "1",
status: fleetnetworkingv1alpha1.ServiceExportStatus{
Conditions: []metav1.Condition{
{
Type: string(fleetnetworkingv1alpha1.ServiceExportValid),
Status: metav1.ConditionFalse,
Reason: "ServiceIneligible",
ObservedGeneration: 3,
},
},
},
wantManifestProcessingAvailabilityResultType: ManifestProcessingAvailabilityResultTypeNotYetAvailable,
},
{
name: "unavailable svcExport (different generation, annotation weight is 1)",
weight: "1",
status: fleetnetworkingv1alpha1.ServiceExportStatus{
Conditions: []metav1.Condition{
{
Type: string(fleetnetworkingv1alpha1.ServiceExportValid),
Status: metav1.ConditionTrue,
Reason: "ServiceIsValid",
ObservedGeneration: 3,
},
{
Type: string(fleetnetworkingv1alpha1.ServiceExportConflict),
Status: metav1.ConditionTrue,
Reason: "ConflictFound",
ObservedGeneration: 2,
},
},
},
wantManifestProcessingAvailabilityResultType: ManifestProcessingAvailabilityResultTypeNotYetAvailable,
},
{
name: "unavailable svcExport (no annotation weight, no conflict condition)",
weight: "",
status: fleetnetworkingv1alpha1.ServiceExportStatus{
Conditions: []metav1.Condition{
{
Type: string(fleetnetworkingv1alpha1.ServiceExportValid),
Status: metav1.ConditionTrue,
Reason: "ServiceIsValid",
ObservedGeneration: 3,
},
},
},
wantManifestProcessingAvailabilityResultType: ManifestProcessingAvailabilityResultTypeNotYetAvailable,
},
{
name: "available svcExport (no annotation weight)",
weight: "",
status: fleetnetworkingv1alpha1.ServiceExportStatus{
Conditions: []metav1.Condition{
{
Type: string(fleetnetworkingv1alpha1.ServiceExportValid),
Status: metav1.ConditionTrue,
Reason: "ServiceIsValid",
ObservedGeneration: 3,
},
{
Type: string(fleetnetworkingv1alpha1.ServiceExportConflict),
Status: metav1.ConditionFalse,
Reason: "NoConflictFound",
ObservedGeneration: 3,
},
},
},
wantManifestProcessingAvailabilityResultType: ManifestProcessingAvailabilityResultTypeAvailable,
},
{
name: "unavailable svcExport (no annotation weight with conflict)",
weight: "",
status: fleetnetworkingv1alpha1.ServiceExportStatus{
Conditions: []metav1.Condition{
{
Type: string(fleetnetworkingv1alpha1.ServiceExportValid),
Status: metav1.ConditionTrue,
Reason: "ServiceIsValid",
ObservedGeneration: 3,
},
{
Type: string(fleetnetworkingv1alpha1.ServiceExportConflict),
Status: metav1.ConditionTrue,
Reason: "ConflictFound",
ObservedGeneration: 3,
},
},
},
wantManifestProcessingAvailabilityResultType: ManifestProcessingAvailabilityResultTypeNotYetAvailable,
},
{
name: "unavailable svcExport (no annotation weight, different generation)",
weight: "",
status: fleetnetworkingv1alpha1.ServiceExportStatus{
Conditions: []metav1.Condition{
{
Type: string(fleetnetworkingv1alpha1.ServiceExportValid),
Status: metav1.ConditionTrue,
Reason: "ServiceIsValid",
ObservedGeneration: 3,
},
{
Type: string(fleetnetworkingv1alpha1.ServiceExportConflict),
Status: metav1.ConditionFalse,
Reason: "NoConflictFound",
ObservedGeneration: 2,
},
},
},
wantManifestProcessingAvailabilityResultType: ManifestProcessingAvailabilityResultTypeNotYetAvailable,
},
{
name: "unavailable svcExport (no annotation weight, invalid service export)",
weight: "",
status: fleetnetworkingv1alpha1.ServiceExportStatus{
Conditions: []metav1.Condition{
{
Type: string(fleetnetworkingv1alpha1.ServiceExportValid),
Status: metav1.ConditionFalse,
Reason: "ServiceIsNotValid",
ObservedGeneration: 3,
},
},
},
wantManifestProcessingAvailabilityResultType: ManifestProcessingAvailabilityResultTypeNotYetAvailable,
},
{
name: "unavailable svcExport (invalid weight)",
weight: "a",
status: fleetnetworkingv1alpha1.ServiceExportStatus{
Conditions: []metav1.Condition{
{
Type: string(fleetnetworkingv1alpha1.ServiceExportValid),
Status: metav1.ConditionTrue,
Reason: "ServiceIsValid",
ObservedGeneration: 3,
},
},
},
wantManifestProcessingAvailabilityResultType: ManifestProcessingAvailabilityResultTypeNotYetAvailable,
},
{
name: "unavailable svcExport (out of range weight)",
weight: "1002",
status: fleetnetworkingv1alpha1.ServiceExportStatus{
Conditions: []metav1.Condition{
{
Type: string(fleetnetworkingv1alpha1.ServiceExportValid),
Status: metav1.ConditionTrue,
Reason: "ServiceIsValid",
ObservedGeneration: 3,
},
},
},
wantManifestProcessingAvailabilityResultType: ManifestProcessingAvailabilityResultTypeNotYetAvailable,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
svcExport := svcExportTemplate.DeepCopy()
if tc.weight != "" {
svcExport.Annotations[objectmeta.ServiceExportAnnotationWeight] = tc.weight
}
svcExport.Status = tc.status
gotResTyp, err := trackServiceExportAvailability(toUnstructured(t, svcExport))
if err != nil {
t.Fatalf("trackServiceExportAvailability() = %v, want no error", err)
}

// Check the result type
if gotResTyp != tc.wantManifestProcessingAvailabilityResultType {
t.Errorf("manifestProcessingAvailabilityResultType = %v, want %v", gotResTyp, tc.wantManifestProcessingAvailabilityResultType)
}
})
}
}

// TestTrackInMemberClusterObjAvailability tests the trackInMemberClusterObjAvailability method.
func TestTrackInMemberClusterObjAvailability(t *testing.T) {
ctx := context.Background()
Expand Down
Loading
Loading