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
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,15 @@ Adding a new version? You'll need three changes:

### Fixed

- Do not skip the gateway listeners without `Programmed` condition set to `True`
when the gateway class does not contain `konghq.com/gateway-unmanaged`
annotation in extracting certificates from listeners. This fixes the issue
that KIC deletes the certificates of listeners on dataplane pods deleted when
KIC is running under the control of Kong gateway operator.
[#7666](https://github.com/Kong/kubernetes-ingress-controller/pull/7666)
- Fix the issue that invalid label value causing KIC failed to store the license
from Konnect into `Secret`.
[#7648](https://github.com/Kong/kubernetes-ingress-controller/pull/7648)
from Konnect into `Secret`.
[#7648](https://github.com/Kong/kubernetes-ingress-controller/pull/7648)

## [3.5.0]

Expand Down
5 changes: 5 additions & 0 deletions hack/generators/cache-stores/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ var supportedTypes = []cacheStoreSupportedType{
Type: "Gateway",
Package: "gatewayapi",
},
{
Type: "GatewayClass",
Package: "gatewayapi",
KeyFunc: clusterWideKeyFunc,
},
{
Type: "BackendTLSPolicy",
Package: "gatewayapi",
Expand Down
3 changes: 3 additions & 0 deletions internal/controllers/gateway/gateway_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ func (r *GatewayReconciler) SetupWithManager(mgr ctrl.Manager) error {
Log: r.Log.WithName(strings.ToUpper(gatewayapi.V1GroupVersion) + "GatewayClass"),
Scheme: r.Scheme,
CacheSyncTimeout: r.CacheSyncTimeout,

DataplaneClient: r.DataplaneClient,
}

return gwcCTRL.SetupWithManager(mgr)
Expand Down Expand Up @@ -181,6 +183,7 @@ func (r *GatewayReconciler) gatewayHasMatchingGatewayClass(obj client.Object) bo
r.Log.Error(err, "Could not retrieve gatewayclass", "gatewayclass", gateway.Spec.GatewayClassName)
return false
}

return isGatewayClassControlled(gatewayClass)
}

Expand Down
10 changes: 10 additions & 0 deletions internal/controllers/gateway/gatewayclass_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

"github.com/kong/kubernetes-ingress-controller/v3/internal/controllers"
"github.com/kong/kubernetes-ingress-controller/v3/internal/gatewayapi"
"github.com/kong/kubernetes-ingress-controller/v3/internal/logging"
"github.com/kong/kubernetes-ingress-controller/v3/internal/util"
Expand Down Expand Up @@ -59,6 +60,8 @@ type GatewayClassReconciler struct { //nolint:revive
Log logr.Logger
Scheme *runtime.Scheme
CacheSyncTimeout time.Duration

DataplaneClient controllers.DataPlane
}

// SetupWithManager sets up the controller with the Manager.
Expand Down Expand Up @@ -144,6 +147,13 @@ func (r *GatewayClassReconciler) Reconcile(ctx context.Context, req ctrl.Request
setGatewayClassCondition(gwc, acceptedCondtion)
return ctrl.Result{}, r.Status().Update(ctx, pruneGatewayClassStatusConds(gwc))
}

// Add the gatewayclass to the translation cache if the gatewayclass is managed by the KIC instance.
err := r.DataplaneClient.UpdateObject(gwc)
if err != nil {
debug(log, gwc, "Failed to update GatewayClass in dataplane, requeueing")
return ctrl.Result{}, err
}
}

return ctrl.Result{}, nil
Expand Down
1 change: 1 addition & 0 deletions internal/dataplane/fallback/graph_dependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func ResolveDependencies(cache store.CacheStores, obj client.Object) ([]client.O
*discoveryv1.EndpointSlice,
*gatewayapi.ReferenceGrant,
*gatewayapi.Gateway,
*gatewayapi.GatewayClass,
*gatewayapi.BackendTLSPolicy,
*configurationv1.KongIngress,
*configurationv1beta1.KongUpstreamPolicy,
Expand Down
38 changes: 27 additions & 11 deletions internal/dataplane/translator/translate_certs.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import (

"github.com/go-logr/logr"
"github.com/kong/go-kong/kong"
"github.com/samber/lo"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

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

// Skip the gateway when the gateway's GatewayClass is not controlled by the KIC instance.
if gwc.Spec.ControllerName != gatewayapi.GatewayController(t.gatewayControllerName) {
continue
}

statuses := lo.SliceToMap(gateway.Status.Listeners, func(status gatewayapi.ListenerStatus) (gatewayapi.SectionName, gatewayapi.ListenerStatus) {
return status.Name, status
})

for _, listener := range gateway.Spec.Listeners {
status, ok := statuses[listener.Name]
if !ok {
Expand All @@ -72,14 +84,18 @@ func (t *Translator) getGatewayCerts() []certWrapper {
continue
}

// Check if listener is marked as programmed
if !util.CheckCondition(
status.Conditions,
util.ConditionType(gatewayapi.ListenerConditionProgrammed),
util.ConditionReason(gatewayapi.ListenerReasonProgrammed),
metav1.ConditionTrue,
gateway.Generation,
) {
// Check if listener is marked as programmed when the gateway's GatewayClass has the "Unmanaged" annotation.
// If the GatewayClass does not have the annotation, the gateway is considered to be managed by other components (for example Kong Operator),
// so we do not check the "Programmed" condition before extracting the certificate from the listener
// to prevent unexpected deletion of certificates when the instance is managed by Kong Operator.
if annotations.ExtractUnmanagedGatewayClassMode(gwc.Annotations) != "" &&
!util.CheckCondition(
status.Conditions,
util.ConditionType(gatewayapi.ListenerConditionProgrammed),
util.ConditionReason(gatewayapi.ListenerReasonProgrammed),
metav1.ConditionTrue,
gateway.Generation,
) {
continue
}

Expand Down
10 changes: 8 additions & 2 deletions internal/dataplane/translator/translator.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@ type Translator struct {
failuresCollector *failures.ResourceFailuresCollector
translatedObjectsCollector *ObjectsCollector

clusterDomain string
enableDrainSupport bool
clusterDomain string
enableDrainSupport bool
gatewayControllerName string
}

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

// ClusterDomain is the cluster domain used for translating Kubernetes objects.
ClusterDomain string

// GatewayControllerName is the gateway controller name used by KIC.
// GatewayClasses with this controller name in spec.ControllerName are managed by KIC, otherwise they are managed by other (like Kong Operator).
GatewayControllerName string
}

// NewTranslator produces a new Translator object provided a logging mechanism
Expand Down Expand Up @@ -152,6 +157,7 @@ func NewTranslator(
translatedObjectsCollector: translatedObjectsCollector,
clusterDomain: config.ClusterDomain,
enableDrainSupport: config.EnableDrainSupport,
gatewayControllerName: config.GatewayControllerName,
}, nil
}

Expand Down
5 changes: 3 additions & 2 deletions internal/manager/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,9 @@ func New(

configTranslator, err := translator.NewTranslator(logger, storer, c.KongWorkspace, kongSemVersion, translatorFeatureFlags, NewSchemaServiceGetter(clientsManager),
translator.Config{
ClusterDomain: c.ClusterDomain,
EnableDrainSupport: c.EnableDrainSupport,
ClusterDomain: c.ClusterDomain,
EnableDrainSupport: c.EnableDrainSupport,
GatewayControllerName: c.GatewayAPIControllerName,
},
)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions internal/store/fake_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type FakeObjects struct {
GRPCRoutes []*gatewayapi.GRPCRoute
ReferenceGrants []*gatewayapi.ReferenceGrant
Gateways []*gatewayapi.Gateway
GatewayClasses []*gatewayapi.GatewayClass
BackendTLSPolicies []*gatewayapi.BackendTLSPolicy
TCPIngresses []*configurationv1beta1.TCPIngress
UDPIngresses []*configurationv1beta1.UDPIngress
Expand Down
13 changes: 13 additions & 0 deletions internal/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ type Storer interface {

// Gateway API resources.
GetGateway(namespace string, name string) (*gatewayapi.Gateway, error)
GetGatewayClass(name string) (*gatewayapi.GatewayClass, error)
ListHTTPRoutes() ([]*gatewayapi.HTTPRoute, error)
ListUDPRoutes() ([]*gatewayapi.UDPRoute, error)
ListTCPRoutes() ([]*gatewayapi.TCPRoute, error)
Expand Down Expand Up @@ -607,6 +608,18 @@ func (s Store) GetGateway(namespace string, name string) (*gatewayapi.Gateway, e
return obj.(*gatewayapi.Gateway), nil
}

// GetGatewayClass returns gatewayclass resource having the specified name.
func (s Store) GetGatewayClass(name string) (*gatewayapi.GatewayClass, error) {
obj, exists, err := s.stores.GatewayClass.GetByKey(name)
if err != nil {
return nil, err
}
if !exists {
return nil, NotFoundError{fmt.Sprintf("GatewayClass %v not found", name)}
}
return obj.(*gatewayapi.GatewayClass), nil
}

// GetKongVault returns kongvault resource having specified name.
func (s Store) GetKongVault(name string) (*configurationv1alpha1.KongVault, error) {
p, exists, err := s.stores.KongVault.GetByKey(name)
Expand Down
10 changes: 10 additions & 0 deletions internal/store/zz_generated.cache_stores.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions internal/store/zz_generated.cache_stores_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading