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
47 changes: 44 additions & 3 deletions internal/controller/gateway_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package controller

import (
"context"
"errors"
"fmt"
"reflect"

Expand Down Expand Up @@ -42,7 +43,15 @@ func (r *GatewayReconciler) SetupWithManager(mgr ctrl.Manager) error {
predicate.NewPredicateFuncs(r.checkGatewayClass),
),
).
WithEventFilter(predicate.GenerationChangedPredicate{}).
WithEventFilter(
predicate.Or(
predicate.GenerationChangedPredicate{},
predicate.NewPredicateFuncs(func(obj client.Object) bool {
_, ok := obj.(*corev1.Secret)
return ok
}),
),
).
Watches(
&gatewayv1.GatewayClass{},
handler.EnqueueRequestsFromMapFunc(r.listGatewayForGatewayClass),
Expand All @@ -58,6 +67,10 @@ func (r *GatewayReconciler) SetupWithManager(mgr ctrl.Manager) error {
&v1alpha1.GatewayProxy{},
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForGatewayProxy),
).
Watches(
&corev1.Secret{},
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForSecret),
).
Complete(r)
}

Expand Down Expand Up @@ -295,6 +308,34 @@ func (r *GatewayReconciler) listGatewaysForHTTPRoute(ctx context.Context, obj cl
return recs
}

func (r *GatewayReconciler) listGatewaysForSecret(ctx context.Context, obj client.Object) (requests []reconcile.Request) {
secret, ok := obj.(*corev1.Secret)
if !ok {
r.Log.Error(
errors.New("unexpected object type"),
"Secret watch predicate received unexpected object type",
"expected", FullTypeName(new(corev1.Secret)), "found", FullTypeName(obj),
)
return nil
}
var gatewayList gatewayv1.GatewayList
if err := r.List(ctx, &gatewayList, client.MatchingFields{
indexer.SecretIndexRef: indexer.GenIndexKey(secret.GetNamespace(), secret.GetName()),
}); err != nil {
r.Log.Error(err, "failed to list gateways")
return nil
}
for _, gateway := range gatewayList.Items {
requests = append(requests, reconcile.Request{
NamespacedName: types.NamespacedName{
Namespace: gateway.GetNamespace(),
Name: gateway.GetName(),
},
})
}
return requests
}

func (r *GatewayReconciler) processInfrastructure(tctx *provider.TranslateContext, gateway *gatewayv1.Gateway) error {
rk := provider.ResourceKind{
Kind: gateway.Kind,
Expand All @@ -316,12 +357,12 @@ func (r *GatewayReconciler) processListenerConfig(tctx *provider.TranslateContex
if ref.Namespace != nil {
ns = string(*ref.Namespace)
}
if ref.Kind != nil && *ref.Kind == gatewayv1.Kind("Secret") {
if ref.Kind != nil && *ref.Kind == KindSecret {
if err := r.Get(context.Background(), client.ObjectKey{
Namespace: ns,
Name: string(ref.Name),
}, &secret); err != nil {
log.Error(err, "failed to get secret", "namespace", ns, "name", string(ref.Name))
log.Error(err, "failed to get secret", "namespace", ns, "name", ref.Name)
SetGatewayListenerConditionProgrammed(gateway, string(listener.Name), false, err.Error())
SetGatewayListenerConditionResolvedRefs(gateway, string(listener.Name), false, err.Error())
break
Expand Down
67 changes: 47 additions & 20 deletions internal/controller/indexer/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,19 @@ const (
)

func SetupIndexer(mgr ctrl.Manager) error {
if err := setupGatewayIndexer(mgr); err != nil {
return err
}
if err := setupHTTPRouteIndexer(mgr); err != nil {
return err
}
if err := setupIngressIndexer(mgr); err != nil {
return err
}
if err := setupConsumerIndexer(mgr); err != nil {
return err
}
if err := setupBackendTrafficPolicyIndexer(mgr); err != nil {
return err
}
if err := setupIngressClassIndexer(mgr); err != nil {
return err
}
if err := setupGatewayProxyIndexer(mgr); err != nil {
return err
for _, setup := range []func(ctrl.Manager) error{
setupGatewayIndexer,
setupHTTPRouteIndexer,
setupIngressIndexer,
setupConsumerIndexer,
setupBackendTrafficPolicyIndexer,
setupIngressClassIndexer,
setupGatewayProxyIndexer,
setupGatewaySecretIndex,
} {
if err := setup(mgr); err != nil {
return err
}
}
return nil
}
Expand Down Expand Up @@ -191,6 +184,15 @@ func setupGatewayProxyIndexer(mgr ctrl.Manager) error {
return nil
}

Copy link

Copilot AI Apr 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Consider adding inline documentation for setupGatewaySecretIndex to clarify its purpose and expected behavior for indexing Secret resources.

Suggested change
// setupGatewaySecretIndex creates an index for Gateway resources based on their associated Secrets.
// This index allows quick lookups of Gateways that reference specific Secrets, using the custom
// GatewaySecretIndexFunc to generate the index keys.

Copilot uses AI. Check for mistakes.
func setupGatewaySecretIndex(mgr ctrl.Manager) error {
return mgr.GetFieldIndexer().IndexField(
context.Background(),
&gatewayv1.Gateway{},
SecretIndexRef,
GatewaySecretIndexFunc,
)
}

func GatewayProxySecretIndexFunc(rawObj client.Object) []string {
gatewayProxy := rawObj.(*v1alpha1.GatewayProxy)
secretKeys := make([]string, 0)
Expand Down Expand Up @@ -310,6 +312,31 @@ func IngressSecretIndexFunc(rawObj client.Object) []string {
return secrets
}

func GatewaySecretIndexFunc(rawObj client.Object) (keys []string) {
gateway := rawObj.(*gatewayv1.Gateway)
var m = make(map[string]struct{})
for _, listener := range gateway.Spec.Listeners {
if listener.TLS == nil || len(listener.TLS.CertificateRefs) == 0 {
continue
}
for _, ref := range listener.TLS.CertificateRefs {
if ref.Kind == nil || *ref.Kind != "Secret" {
continue
}
namespace := gateway.GetNamespace()
if ref.Namespace != nil {
namespace = string(*ref.Namespace)
}
key := GenIndexKey(namespace, string(ref.Name))
if _, ok := m[key]; !ok {
m[key] = struct{}{}
keys = append(keys, key)
}
}
}
return keys
}

func GenIndexKeyWithGK(group, kind, namespace, name string) string {
gvk := schema.GroupKind{
Group: group,
Expand Down
14 changes: 14 additions & 0 deletions internal/controller/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package controller
import (
"context"
"fmt"
"path"
"reflect"
"strings"

"github.com/api7/gopkg/pkg/log"
Expand All @@ -29,6 +31,7 @@ const (
KindIngress = "Ingress"
KindIngressClass = "IngressClass"
KindGatewayProxy = "GatewayProxy"
KindSecret = "Secret"
)

const defaultIngressClassAnnotation = "ingressclass.kubernetes.io/is-default-class"
Expand Down Expand Up @@ -839,3 +842,14 @@ func ProcessGatewayProxy(r client.Client, tctx *provider.TranslateContext, gatew

return nil
}

// FullTypeName returns the fully qualified name of the type of the given value.
func FullTypeName(a any) string {
typeOf := reflect.TypeOf(a)
pkgPath := typeOf.PkgPath()
name := typeOf.String()
if typeOf.Kind() == reflect.Ptr {
pkgPath = typeOf.Elem().PkgPath()
}
return path.Join(path.Dir(pkgPath), name)
}
22 changes: 17 additions & 5 deletions test/e2e/gatewayapi/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ spec:
`

Context("Gateway", func() {
var defautlGatewayClass = `
var defaultGatewayClass = `
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
Expand All @@ -57,7 +57,7 @@ spec:
controllerName: "apisix.apache.org/api7-ingress-controller"
`

var defautlGateway = `
var defaultGateway = `
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
Expand Down Expand Up @@ -101,7 +101,7 @@ spec:
time.Sleep(5 * time.Second)

By("create GatewayClass")
err = s.CreateResourceFromStringWithNamespace(defautlGatewayClass, "")
err = s.CreateResourceFromStringWithNamespace(defaultGatewayClass, "")
Expect(err).NotTo(HaveOccurred(), "creating GatewayClass")
time.Sleep(5 * time.Second)

Expand All @@ -112,7 +112,7 @@ spec:
Expect(gcyaml).To(ContainSubstring("message: the gatewayclass has been accepted by the api7-ingress-controller"), "checking GatewayClass condition message")

By("create Gateway")
err = s.CreateResourceFromStringWithNamespace(defautlGateway, s.CurrentNamespace())
err = s.CreateResourceFromStringWithNamespace(defaultGateway, s.CurrentNamespace())
Expect(err).NotTo(HaveOccurred(), "creating Gateway")
time.Sleep(5 * time.Second)

Expand Down Expand Up @@ -196,7 +196,7 @@ spec:
})

Context("Gateway SSL with and without hostname", func() {
It("Check if SSL resource was created", func() {
It("Check if SSL resource was created and updated", func() {
By("create GatewayProxy")
gatewayProxy := fmt.Sprintf(gatewayProxyYaml, framework.DashboardTLSEndpoint, s.AdminKey())
err := s.CreateResourceFromString(gatewayProxy)
Expand Down Expand Up @@ -266,6 +266,18 @@ spec:
assert.Len(GinkgoT(), tls, 1, "tls number not expect")
assert.Equal(GinkgoT(), Cert, tls[0].Cert, "tls cert not expect")
assert.Equal(GinkgoT(), tls[0].Labels["k8s/controller-name"], "apisix.apache.org/api7-ingress-controller")

By("update secret")
err = s.NewKubeTlsSecret(secretName, framework.TestCert, framework.TestKey)
Expect(err).NotTo(HaveOccurred(), "update secret")
Eventually(func() string {
tls, err := s.DefaultDataplaneResource().SSL().List(context.Background())
Expect(err).NotTo(HaveOccurred(), "list ssl from dashboard")
if len(tls) < 1 {
return ""
}
return tls[0].Cert
}).WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(framework.TestCert))
})
})
})
Expand Down
Loading