Support for cross-namespace references / GatewayAPI ReferenceGrants

This commit is contained in:
Pascal Hofmann 2024-01-30 16:44:05 +01:00 committed by GitHub
parent 8b77f0c2dd
commit 9be523d772
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 940 additions and 67 deletions

View file

@ -19,6 +19,7 @@ import (
"k8s.io/client-go/tools/clientcmd"
gatev1 "sigs.k8s.io/gateway-api/apis/v1"
gatev1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
gatev1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
gateclientset "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned"
gateinformers "sigs.k8s.io/gateway-api/pkg/client/informers/externalversions"
)
@ -34,13 +35,7 @@ func (reh *resourceEventHandler) OnAdd(obj interface{}, isInInitialList bool) {
}
func (reh *resourceEventHandler) OnUpdate(oldObj, newObj interface{}) {
switch oldObj.(type) {
case *gatev1.GatewayClass:
// Skip update for gateway classes. We only manage addition or deletion for this cluster-wide resource.
return
default:
eventHandlerFunc(reh.ev, newObj)
}
eventHandlerFunc(reh.ev, newObj)
}
func (reh *resourceEventHandler) OnDelete(obj interface{}) {
@ -59,6 +54,7 @@ type Client interface {
GetHTTPRoutes(namespaces []string) ([]*gatev1.HTTPRoute, error)
GetTCPRoutes(namespaces []string) ([]*gatev1alpha2.TCPRoute, error)
GetTLSRoutes(namespaces []string) ([]*gatev1alpha2.TLSRoute, error)
GetReferenceGrants(namespace string) ([]*gatev1beta1.ReferenceGrant, error)
GetService(namespace, name string) (*corev1.Service, bool, error)
GetSecret(namespace, name string) (*corev1.Secret, bool, error)
GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error)
@ -189,9 +185,6 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
return nil, err
}
// TODO manage Reference Policy
// https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.ReferencePolicy
for _, ns := range namespaces {
factoryGateway := gateinformers.NewSharedInformerFactoryWithOptions(c.csGateway, resyncPeriod, gateinformers.WithNamespace(ns))
_, err = factoryGateway.Gateway().V1().Gateways().Informer().AddEventHandler(eventHandler)
@ -210,6 +203,10 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
if err != nil {
return nil, err
}
_, err = factoryGateway.Gateway().V1beta1().ReferenceGrants().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
}
factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns))
_, err = factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler)
@ -363,6 +360,21 @@ func (c *clientWrapper) GetTLSRoutes(namespaces []string) ([]*gatev1alpha2.TLSRo
return tlsRoutes, nil
}
func (c *clientWrapper) GetReferenceGrants(namespace string) ([]*gatev1beta1.ReferenceGrant, error) {
if !c.isWatchedNamespace(namespace) {
log.Warn().Msgf("Failed to get ReferenceGrants: %q is not within watched namespaces", namespace)
return nil, fmt.Errorf("failed to get ReferenceGrants: namespace %s is not within watched namespaces", namespace)
}
referenceGrants, err := c.factoriesGateway[c.lookupNamespace(namespace)].Gateway().V1beta1().ReferenceGrants().Lister().ReferenceGrants(namespace).List(labels.Everything())
if err != nil {
return nil, err
}
return referenceGrants, nil
}
func (c *clientWrapper) GetGateways() []*gatev1.Gateway {
var result []*gatev1.Gateway
@ -388,7 +400,7 @@ func (c *clientWrapper) UpdateGatewayClassStatus(gatewayClass *gatev1.GatewayCla
var newConditions []metav1.Condition
for _, cond := range gc.Status.Conditions {
// No update for identical condition.
if cond.Type == condition.Type && cond.Status == condition.Status {
if cond.Type == condition.Type && cond.Status == condition.Status && cond.ObservedGeneration == condition.ObservedGeneration {
return nil
}
@ -470,7 +482,7 @@ func conditionsEquals(conditionsA, conditionsB []metav1.Condition) bool {
for _, conditionA := range conditionsA {
for _, conditionB := range conditionsB {
if conditionA.Type == conditionB.Type {
if conditionA.Reason != conditionB.Reason || conditionA.Status != conditionB.Status || conditionA.Message != conditionB.Message {
if conditionA.Reason != conditionB.Reason || conditionA.Status != conditionB.Status || conditionA.Message != conditionB.Message || conditionA.ObservedGeneration != conditionB.ObservedGeneration {
return false
}
conditionMatches++