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 @@ -29,6 +29,7 @@ require (
k8s.io/client-go v0.34.1
k8s.io/code-generator v0.34.1
k8s.io/klog/v2 v2.130.1
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
knative.dev/serving v0.46.6
)

Expand Down Expand Up @@ -99,7 +100,6 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f // indirect
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
knative.dev/networking v0.0.0-20250902160145-7dad473f6351 // indirect
knative.dev/pkg v0.0.0-20250909011231-077dcf0d00e8 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
Expand Down
20 changes: 20 additions & 0 deletions pkg/router/gateway_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,26 @@ func (gwr *GatewayAPIRouter) GetRoutes(canary *flaggerv1.Canary) (
err = fmt.Errorf("HTTPRoute %s.%s get error: %w", apexSvcName, hrNamespace, err)
return
}

currentGeneration := httpRoute.GetGeneration()
for _, parentRef := range httpRoute.Spec.CommonRouteSpec.ParentRefs {
for _, parentStatus := range httpRoute.Status.Parents {
if !reflect.DeepEqual(parentStatus.ParentRef, parentRef) {
continue
}

for _, condition := range parentStatus.Conditions {
if condition.Type == string(v1.RouteConditionAccepted) && (condition.Status != metav1.ConditionTrue || condition.ObservedGeneration < currentGeneration) {
err = fmt.Errorf(
"HTTPRoute %s.%s parent %s is not ready (status: %s, observed generation: %d, current generation: %d)",
apexSvcName, hrNamespace, parentRef.Name, string(condition.Status), condition.ObservedGeneration, currentGeneration,
)
return 0, 0, false, err
}
}
}
}

var weightedRule *v1.HTTPRouteRule
for _, rule := range httpRoute.Spec.Rules {
// If session affinity is enabled, then we are only interested in the rule
Expand Down
104 changes: 104 additions & 0 deletions pkg/router/gateway_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"

flaggerv1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1"
v1 "github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1"
Expand Down Expand Up @@ -603,3 +604,106 @@ func TestGatewayAPIRouter_makeFilters_CORS(t *testing.T) {
// Assert MaxAge (24h = 86400 seconds)
assert.Equal(t, int32(86400), corsFilter.CORS.MaxAge)
}

func TestGatewayAPIRouter_GetRoutes(t *testing.T) {
canary := newTestGatewayAPICanary()
mocks := newFixture(canary)
router := &GatewayAPIRouter{
gatewayAPIClient: mocks.meshClient,
kubeClient: mocks.kubeClient,
logger: mocks.logger,
}

httpRoute := &v1.HTTPRoute{
ObjectMeta: metav1.ObjectMeta{
Name: "podinfo",
Generation: 1,
},
Spec: v1.HTTPRouteSpec{
Rules: []v1.HTTPRouteRule{
{
BackendRefs: []v1.HTTPBackendRef{
{
BackendRef: v1.BackendRef{
BackendObjectReference: v1.BackendObjectReference{
Name: "podinfo-canary",
},
Weight: ptr.To(int32(10)),
},
},
{
BackendRef: v1.BackendRef{
BackendObjectReference: v1.BackendObjectReference{
Name: "podinfo-primary",
},
Weight: ptr.To(int32(90)),
},
},
},
},
},
CommonRouteSpec: v1.CommonRouteSpec{
ParentRefs: []v1.ParentReference{
{
Name: "podinfo",
},
},
},
},
}
httpRoute, err := router.gatewayAPIClient.GatewayapiV1().HTTPRoutes("default").Create(context.TODO(), httpRoute, metav1.CreateOptions{})
require.NoError(t, err)

t.Run("httproute generation", func(t *testing.T) {
httpRoute.ObjectMeta.Generation = 5
httpRoute.Status.Parents = []v1.RouteParentStatus{
{
ParentRef: v1.ParentReference{
Name: "podinfo",
SectionName: ptr.To(v1.SectionName("https")),
},
Conditions: []metav1.Condition{
{
Type: string(v1.RouteConditionAccepted),
Status: metav1.ConditionTrue,
ObservedGeneration: 1,
},
},
},
{
ParentRef: v1.ParentReference{
Name: "podinfo",
},
Conditions: []metav1.Condition{
{
Type: string(v1.RouteConditionAccepted),
Status: metav1.ConditionFalse,
ObservedGeneration: 4,
},
},
},
}
httpRoute, err := router.gatewayAPIClient.GatewayapiV1().HTTPRoutes("default").Update(context.TODO(), httpRoute, metav1.UpdateOptions{})
require.NoError(t, err)

_, _, _, err = router.GetRoutes(canary)
require.Error(t, err)

httpRoute.Status.Parents[1].Conditions[0].ObservedGeneration = 5
_, err = router.gatewayAPIClient.GatewayapiV1().HTTPRoutes("default").Update(context.TODO(), httpRoute, metav1.UpdateOptions{})
require.NoError(t, err)

_, _, _, err = router.GetRoutes(canary)
require.Error(t, err)

httpRoute.Status.Parents[1].Conditions[0].Status = metav1.ConditionTrue
_, err = router.gatewayAPIClient.GatewayapiV1().HTTPRoutes("default").Update(context.TODO(), httpRoute, metav1.UpdateOptions{})
require.NoError(t, err)

primaryWeight, canaryWeight, mirrored, err := router.GetRoutes(canary)
require.NoError(t, err)
assert.Equal(t, 90, primaryWeight)
assert.Equal(t, 10, canaryWeight)
assert.False(t, mirrored)
})
}
Loading