Skip to content

Commit

Permalink
gateway2/status: preserve external conditions
Browse files Browse the repository at this point in the history
There is a requirement to allow external controllers to update
the statuses on Gateway objects by writing Conditions that do
not conflict with the Types owned by the Gateway. Currently, only
condition.Types that are a part of the status reporter are set as
the final list of conditions. This change allows external controllers
to write Condition.Types that do not conflict.

Signed-off-by: Shashank Ram <[email protected]>
  • Loading branch information
shashankram committed Feb 26, 2025
1 parent 7f648f0 commit 541fc42
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 4 deletions.
12 changes: 12 additions & 0 deletions changelog/v1.19.0-beta13/dbg-status.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
changelog:
- type: NON_USER_FACING
resolvesIssue: false
description: |
gateway2/status: preserve external conditions
There is a requirement to allow external controllers to update
the statuses on Gateway objects by writing Conditions that do
not conflict with the Types owned by the Gateway. Currently, only
condition.Types that are a part of the status reporter are set as
the final list of conditions. This change allows external controllers
to write Condition.Types that do not conflict.
89 changes: 85 additions & 4 deletions projects/gateway2/reports/reporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,26 @@ var _ = Describe("Reporting Infrastructure", func() {
Expect(status.Listeners[0].Conditions).To(HaveLen(4))
})

It("should preserve conditions set externally", func() {
gw := gw()
gw.Status.Conditions = append(gw.Status.Conditions, metav1.Condition{
Type: "gloo.solo.io/SomeCondition",
Status: metav1.ConditionFalse,
})
rm := reports.NewReportMap()

reporter := reports.NewReporter(&rm)
// initialize GatewayReporter to mimic translation loop (i.e. report gets initialized for all GWs)
reporter.Gateway(gw)

status := rm.BuildGWStatus(context.Background(), *gw)

Expect(status).NotTo(BeNil())
Expect(status.Conditions).To(HaveLen(3)) // 2 from the report, 1 from the original status
Expect(status.Listeners).To(HaveLen(1))
Expect(status.Listeners[0].Conditions).To(HaveLen(4))
})

It("should correctly set negative gateway conditions from report and not add extra conditions", func() {
gw := gw()
rm := reports.NewReportMap()
Expand Down Expand Up @@ -133,6 +153,42 @@ var _ = Describe("Reporting Infrastructure", func() {
Entry("delegatee route", delegateeRoute()),
)

DescribeTable("should preserve conditions set externally",
func(obj client.Object) {
rm := reports.NewReportMap()

reporter := reports.NewReporter(&rm)
// initialize RouteReporter to mimic translation loop (i.e. report gets initialized for all Routes)
reporter.Route(obj)

status := rm.BuildRouteStatus(context.Background(), obj, "gloo-gateway")

Expect(status).NotTo(BeNil())
Expect(status.Parents).To(HaveLen(1))
Expect(status.Parents[0].Conditions).To(HaveLen(3)) // 2 from the report, 1 from the original status
},
Entry("regular httproute", httpRoute(
metav1.Condition{
Type: "gloo.solo.io/SomeCondition",
},
)),
Entry("regular tcproute", tcpRoute(
metav1.Condition{
Type: "gloo.solo.io/SomeCondition",
},
)),
Entry("regular tlsroute", tlsRoute(
metav1.Condition{
Type: "gloo.solo.io/SomeCondition",
},
)),
Entry("delegatee route", delegateeRoute(
metav1.Condition{
Type: "gloo.solo.io/SomeCondition",
},
)),
)

DescribeTable("should correctly set negative route conditions from report and not add extra conditions",
func(obj client.Object, parentRef *gwv1.ParentReference) {
rm := reports.NewReportMap()
Expand Down Expand Up @@ -361,36 +417,55 @@ var _ = Describe("Reporting Infrastructure", func() {
)
})

func httpRoute() client.Object {
func httpRoute(conditions ...metav1.Condition) client.Object {
route := &gwv1.HTTPRoute{
ObjectMeta: metav1.ObjectMeta{
Name: "route",
Namespace: "default",
},
}
route.Spec.CommonRouteSpec.ParentRefs = append(route.Spec.CommonRouteSpec.ParentRefs, *parentRef())
if len(conditions) > 0 {
route.Status.Parents = append(route.Status.Parents, gwv1.RouteParentStatus{
ParentRef: *parentRef(),
Conditions: conditions,
})
}

return route
}

func tcpRoute() client.Object {
func tcpRoute(conditions ...metav1.Condition) client.Object {
route := &gwv1a2.TCPRoute{
ObjectMeta: metav1.ObjectMeta{
Name: "route",
Namespace: "default",
},
}
route.Spec.CommonRouteSpec.ParentRefs = append(route.Spec.CommonRouteSpec.ParentRefs, *parentRef())
if len(conditions) > 0 {
route.Status.Parents = append(route.Status.Parents, gwv1.RouteParentStatus{
ParentRef: *parentRef(),
Conditions: conditions,
})
}
return route
}

func tlsRoute() client.Object {
func tlsRoute(conditions ...metav1.Condition) client.Object {
route := &gwv1a2.TLSRoute{
ObjectMeta: metav1.ObjectMeta{
Name: "route",
Namespace: "default",
},
}
route.Spec.CommonRouteSpec.ParentRefs = append(route.Spec.CommonRouteSpec.ParentRefs, *parentRef())
if len(conditions) > 0 {
route.Status.Parents = append(route.Status.Parents, gwv1.RouteParentStatus{
ParentRef: *parentRef(),
Conditions: conditions,
})
}
return route
}

Expand All @@ -400,14 +475,20 @@ func parentRef() *gwv1.ParentReference {
}
}

func delegateeRoute() client.Object {
func delegateeRoute(conditions ...metav1.Condition) client.Object {
route := &gwv1.HTTPRoute{
ObjectMeta: metav1.ObjectMeta{
Name: "child-route",
Namespace: "default",
},
}
route.Spec.CommonRouteSpec.ParentRefs = append(route.Spec.CommonRouteSpec.ParentRefs, *parentRouteRef())
if len(conditions) > 0 {
route.Status.Parents = append(route.Status.Parents, gwv1.RouteParentStatus{
ParentRef: *parentRouteRef(),
Conditions: conditions,
})
}
return route
}

Expand Down
14 changes: 14 additions & 0 deletions projects/gateway2/reports/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ func (r *ReportMap) BuildGWStatus(ctx context.Context, gw gwv1.Gateway) *gwv1.Ga
}
meta.SetStatusCondition(&finalConditions, gwCondition)
}
// If there are conditions on the Gateway that are not owned by our reporter, include
// them in the final list of conditions to preseve conditions we do not own
for _, condition := range gw.Status.Conditions {
if meta.FindStatusCondition(finalConditions, condition.Type) == nil {
finalConditions = append(finalConditions, condition)
}
}

finalGwStatus := gwv1.GatewayStatus{}
finalGwStatus.Conditions = finalConditions
Expand Down Expand Up @@ -138,6 +145,13 @@ func (r *ReportMap) BuildRouteStatus(ctx context.Context, obj client.Object, cNa
}
meta.SetStatusCondition(&finalConditions, pCondition)
}
// If there are conditions on the HTTPRoute that are not owned by our reporter, include
// them in the final list of conditions to preseve conditions we do not own
for _, condition := range currentParentRefConditions {
if meta.FindStatusCondition(finalConditions, condition.Type) == nil {
finalConditions = append(finalConditions, condition)
}
}

routeParentStatus := gwv1.RouteParentStatus{
ParentRef: parentRef,
Expand Down

0 comments on commit 541fc42

Please sign in to comment.