Skip to content

Commit 9f0d81f

Browse files
[Backport release/3.5.x] fix(translator): check gateway class and do not skip listeners when gateway class is not managed by KIC (#7711)
* fix(translator): check gateway class and do not skip listeners when gateway class is not managed by KIC (#7666) * check gateway class and do not skip listeners when gateway class is not managed by KIC * update changelog * store gatewayclass into cache in gwc controller * fix comments and move gwc controller name check after getting gwc (cherry picked from commit 2562662) * fix changlog --------- Co-authored-by: Tao Yi <[email protected]>
1 parent 473defd commit 9f0d81f

File tree

12 files changed

+99
-17
lines changed

12 files changed

+99
-17
lines changed

CHANGELOG.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,26 @@ Adding a new version? You'll need three changes:
109109
- [0.0.5](#005)
110110
- [0.0.4 and prior](#004-and-prior)
111111

112+
## Unreleased
113+
114+
### Fixed
115+
116+
- Do not skip the gateway listeners without `Programmed` condition set to `True`
117+
when the gateway class does not contain `konghq.com/gateway-unmanaged`
118+
annotation in extracting certificates from listeners. This fixes the issue
119+
that KIC deletes the certificates of listeners on dataplane pods deleted when
120+
KIC is running under the control of Kong gateway operator.
121+
[#7666](https://github.com/Kong/kubernetes-ingress-controller/pull/7666)
122+
112123
## [3.5.1]
113124

114125
> Release date: 2025-07-31
115126
116127
### Fixed
117128

118129
- Fix the issue that invalid label value causing KIC failed to store the license
119-
from Konnect into `Secret`.
120-
[#7648](https://github.com/Kong/kubernetes-ingress-controller/pull/7648)
130+
from Konnect into `Secret`.
131+
[#7648](https://github.com/Kong/kubernetes-ingress-controller/pull/7648)
121132

122133
## [3.5.0]
123134

hack/generators/cache-stores/spec.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ var supportedTypes = []cacheStoreSupportedType{
6060
Type: "Gateway",
6161
Package: "gatewayapi",
6262
},
63+
{
64+
Type: "GatewayClass",
65+
Package: "gatewayapi",
66+
KeyFunc: clusterWideKeyFunc,
67+
},
6368
{
6469
Type: "BackendTLSPolicy",
6570
Package: "gatewayapi",

internal/controllers/gateway/gateway_controller.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ func (r *GatewayReconciler) SetupWithManager(mgr ctrl.Manager) error {
143143
Log: r.Log.WithName(strings.ToUpper(gatewayapi.V1GroupVersion) + "GatewayClass"),
144144
Scheme: r.Scheme,
145145
CacheSyncTimeout: r.CacheSyncTimeout,
146+
147+
DataplaneClient: r.DataplaneClient,
146148
}
147149

148150
return gwcCTRL.SetupWithManager(mgr)
@@ -181,6 +183,7 @@ func (r *GatewayReconciler) gatewayHasMatchingGatewayClass(obj client.Object) bo
181183
r.Log.Error(err, "Could not retrieve gatewayclass", "gatewayclass", gateway.Spec.GatewayClassName)
182184
return false
183185
}
186+
184187
return isGatewayClassControlled(gatewayClass)
185188
}
186189

internal/controllers/gateway/gatewayclass_controller.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"sigs.k8s.io/controller-runtime/pkg/predicate"
1919
"sigs.k8s.io/controller-runtime/pkg/reconcile"
2020

21+
"github.com/kong/kubernetes-ingress-controller/v3/internal/controllers"
2122
"github.com/kong/kubernetes-ingress-controller/v3/internal/gatewayapi"
2223
"github.com/kong/kubernetes-ingress-controller/v3/internal/logging"
2324
"github.com/kong/kubernetes-ingress-controller/v3/internal/util"
@@ -59,6 +60,8 @@ type GatewayClassReconciler struct { //nolint:revive
5960
Log logr.Logger
6061
Scheme *runtime.Scheme
6162
CacheSyncTimeout time.Duration
63+
64+
DataplaneClient controllers.DataPlane
6265
}
6366

6467
// SetupWithManager sets up the controller with the Manager.
@@ -144,6 +147,13 @@ func (r *GatewayClassReconciler) Reconcile(ctx context.Context, req ctrl.Request
144147
setGatewayClassCondition(gwc, acceptedCondtion)
145148
return ctrl.Result{}, r.Status().Update(ctx, pruneGatewayClassStatusConds(gwc))
146149
}
150+
151+
// Add the gatewayclass to the translation cache if the gatewayclass is managed by the KIC instance.
152+
err := r.DataplaneClient.UpdateObject(gwc)
153+
if err != nil {
154+
debug(log, gwc, "Failed to update GatewayClass in dataplane, requeueing")
155+
return ctrl.Result{}, err
156+
}
147157
}
148158

149159
return ctrl.Result{}, nil

internal/dataplane/fallback/graph_dependencies.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ func ResolveDependencies(cache store.CacheStores, obj client.Object) ([]client.O
6262
*discoveryv1.EndpointSlice,
6363
*gatewayapi.ReferenceGrant,
6464
*gatewayapi.Gateway,
65+
*gatewayapi.GatewayClass,
6566
*gatewayapi.BackendTLSPolicy,
6667
*configurationv1.KongIngress,
6768
*configurationv1beta1.KongUpstreamPolicy,

internal/dataplane/translator/translate_certs.go

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ import (
99

1010
"github.com/go-logr/logr"
1111
"github.com/kong/go-kong/kong"
12+
"github.com/samber/lo"
1213
corev1 "k8s.io/api/core/v1"
1314
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1415

16+
"github.com/kong/kubernetes-ingress-controller/v3/internal/annotations"
1517
"github.com/kong/kubernetes-ingress-controller/v3/internal/dataplane/kongstate"
1618
"github.com/kong/kubernetes-ingress-controller/v3/internal/gatewayapi"
1719
"github.com/kong/kubernetes-ingress-controller/v3/internal/logging"
@@ -55,11 +57,21 @@ func (t *Translator) getGatewayCerts() []certWrapper {
5557
return certs
5658
}
5759
for _, gateway := range gateways {
58-
statuses := make(map[gatewayapi.SectionName]gatewayapi.ListenerStatus, len(gateway.Status.Listeners))
59-
for _, status := range gateway.Status.Listeners {
60-
statuses[status.Name] = status
60+
gwc, err := s.GetGatewayClass(string(gateway.Spec.GatewayClassName))
61+
if err != nil {
62+
logger.Error(err, "Failed to get GatewayClass for Gateway, skipping", "gateway", gateway.Name, "gateway_class", gateway.Spec.GatewayClassName)
63+
continue
6164
}
6265

66+
// Skip the gateway when the gateway's GatewayClass is not controlled by the KIC instance.
67+
if gwc.Spec.ControllerName != gatewayapi.GatewayController(t.gatewayControllerName) {
68+
continue
69+
}
70+
71+
statuses := lo.SliceToMap(gateway.Status.Listeners, func(status gatewayapi.ListenerStatus) (gatewayapi.SectionName, gatewayapi.ListenerStatus) {
72+
return status.Name, status
73+
})
74+
6375
for _, listener := range gateway.Spec.Listeners {
6476
status, ok := statuses[listener.Name]
6577
if !ok {
@@ -72,14 +84,18 @@ func (t *Translator) getGatewayCerts() []certWrapper {
7284
continue
7385
}
7486

75-
// Check if listener is marked as programmed
76-
if !util.CheckCondition(
77-
status.Conditions,
78-
util.ConditionType(gatewayapi.ListenerConditionProgrammed),
79-
util.ConditionReason(gatewayapi.ListenerReasonProgrammed),
80-
metav1.ConditionTrue,
81-
gateway.Generation,
82-
) {
87+
// Check if listener is marked as programmed when the gateway's GatewayClass has the "Unmanaged" annotation.
88+
// If the GatewayClass does not have the annotation, the gateway is considered to be managed by other components (for example Kong Operator),
89+
// so we do not check the "Programmed" condition before extracting the certificate from the listener
90+
// to prevent unexpected deletion of certificates when the instance is managed by Kong Operator.
91+
if annotations.ExtractUnmanagedGatewayClassMode(gwc.Annotations) != "" &&
92+
!util.CheckCondition(
93+
status.Conditions,
94+
util.ConditionType(gatewayapi.ListenerConditionProgrammed),
95+
util.ConditionReason(gatewayapi.ListenerReasonProgrammed),
96+
metav1.ConditionTrue,
97+
gateway.Generation,
98+
) {
8399
continue
84100
}
85101

internal/dataplane/translator/translator.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,9 @@ type Translator struct {
109109
failuresCollector *failures.ResourceFailuresCollector
110110
translatedObjectsCollector *ObjectsCollector
111111

112-
clusterDomain string
113-
enableDrainSupport bool
112+
clusterDomain string
113+
enableDrainSupport bool
114+
gatewayControllerName string
114115
}
115116

116117
// Config is a configuration for the Translator.
@@ -120,6 +121,10 @@ type Config struct {
120121

121122
// ClusterDomain is the cluster domain used for translating Kubernetes objects.
122123
ClusterDomain string
124+
125+
// GatewayControllerName is the gateway controller name used by KIC.
126+
// GatewayClasses with this controller name in spec.ControllerName are managed by KIC, otherwise they are managed by other (like Kong Operator).
127+
GatewayControllerName string
123128
}
124129

125130
// NewTranslator produces a new Translator object provided a logging mechanism
@@ -152,6 +157,7 @@ func NewTranslator(
152157
translatedObjectsCollector: translatedObjectsCollector,
153158
clusterDomain: config.ClusterDomain,
154159
enableDrainSupport: config.EnableDrainSupport,
160+
gatewayControllerName: config.GatewayControllerName,
155161
}, nil
156162
}
157163

internal/manager/run.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,9 @@ func New(
221221

222222
configTranslator, err := translator.NewTranslator(logger, storer, c.KongWorkspace, kongSemVersion, translatorFeatureFlags, NewSchemaServiceGetter(clientsManager),
223223
translator.Config{
224-
ClusterDomain: c.ClusterDomain,
225-
EnableDrainSupport: c.EnableDrainSupport,
224+
ClusterDomain: c.ClusterDomain,
225+
EnableDrainSupport: c.EnableDrainSupport,
226+
GatewayControllerName: c.GatewayAPIControllerName,
226227
},
227228
)
228229
if err != nil {

internal/store/fake_store.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type FakeObjects struct {
4141
GRPCRoutes []*gatewayapi.GRPCRoute
4242
ReferenceGrants []*gatewayapi.ReferenceGrant
4343
Gateways []*gatewayapi.Gateway
44+
GatewayClasses []*gatewayapi.GatewayClass
4445
BackendTLSPolicies []*gatewayapi.BackendTLSPolicy
4546
TCPIngresses []*configurationv1beta1.TCPIngress
4647
UDPIngresses []*configurationv1beta1.UDPIngress

internal/store/store.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ type Storer interface {
9999

100100
// Gateway API resources.
101101
GetGateway(namespace string, name string) (*gatewayapi.Gateway, error)
102+
GetGatewayClass(name string) (*gatewayapi.GatewayClass, error)
102103
ListHTTPRoutes() ([]*gatewayapi.HTTPRoute, error)
103104
ListUDPRoutes() ([]*gatewayapi.UDPRoute, error)
104105
ListTCPRoutes() ([]*gatewayapi.TCPRoute, error)
@@ -607,6 +608,18 @@ func (s Store) GetGateway(namespace string, name string) (*gatewayapi.Gateway, e
607608
return obj.(*gatewayapi.Gateway), nil
608609
}
609610

611+
// GetGatewayClass returns gatewayclass resource having the specified name.
612+
func (s Store) GetGatewayClass(name string) (*gatewayapi.GatewayClass, error) {
613+
obj, exists, err := s.stores.GatewayClass.GetByKey(name)
614+
if err != nil {
615+
return nil, err
616+
}
617+
if !exists {
618+
return nil, NotFoundError{fmt.Sprintf("GatewayClass %v not found", name)}
619+
}
620+
return obj.(*gatewayapi.GatewayClass), nil
621+
}
622+
610623
// GetKongVault returns kongvault resource having specified name.
611624
func (s Store) GetKongVault(name string) (*configurationv1alpha1.KongVault, error) {
612625
p, exists, err := s.stores.KongVault.GetByKey(name)

0 commit comments

Comments
 (0)