Skip to content

Commit 0191a5e

Browse files
committed
chore: Refactor indexer setup and enhance Gateway secret handling
Refactored the `SetupIndexer` function to use a loop for registering indexers, added a new `setupGatewaySecretIndex` function, and implemented secret watching in the Gateway reconciler. These changes improve code maintainability and enable dynamic reconciliation of Gateways when referenced secrets are updated.
1 parent 100bbc8 commit 0191a5e

File tree

4 files changed

+129
-29
lines changed

4 files changed

+129
-29
lines changed

internal/controller/gateway_controller.go

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ package controller
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"reflect"
78

8-
"github.com/api7/gopkg/pkg/log"
99
"github.com/go-logr/logr"
1010
corev1 "k8s.io/api/core/v1"
1111
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -19,11 +19,15 @@ import (
1919
"sigs.k8s.io/controller-runtime/pkg/reconcile"
2020
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
2121

22+
"github.com/api7/gopkg/pkg/log"
23+
2224
"github.com/api7/api7-ingress-controller/api/v1alpha1"
2325
"github.com/api7/api7-ingress-controller/internal/controller/indexer"
2426
"github.com/api7/api7-ingress-controller/internal/provider"
2527
)
2628

29+
// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch
30+
2731
// GatewayReconciler reconciles a Gateway object.
2832
type GatewayReconciler struct { //nolint:revive
2933
client.Client
@@ -58,10 +62,21 @@ func (r *GatewayReconciler) SetupWithManager(mgr ctrl.Manager) error {
5862
&v1alpha1.GatewayProxy{},
5963
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForGatewayProxy),
6064
).
65+
Watches(
66+
&corev1.Secret{},
67+
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForSecret),
68+
builder.WithPredicates(
69+
predicate.NewPredicateFuncs(func(_ client.Object) bool {
70+
return true
71+
}),
72+
),
73+
).
6174
Complete(r)
6275
}
6376

6477
func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
78+
r.Log.Info("request Reconcile")
79+
6580
gateway := new(gatewayv1.Gateway)
6681
if err := r.Get(ctx, req.NamespacedName, gateway); err != nil {
6782
if client.IgnoreNotFound(err) == nil {
@@ -295,6 +310,36 @@ func (r *GatewayReconciler) listGatewaysForHTTPRoute(ctx context.Context, obj cl
295310
return recs
296311
}
297312

313+
func (r *GatewayReconciler) listGatewaysForSecret(ctx context.Context, obj client.Object) (requests []reconcile.Request) {
314+
secret, ok := obj.(*corev1.Secret)
315+
if !ok {
316+
r.Log.Error(
317+
errors.New("unexpected object type"),
318+
"Secret watch predicate received unexpected object type",
319+
"expected", FullTypeName(new(corev1.Secret)), "found", FullTypeName(obj),
320+
)
321+
return nil
322+
}
323+
r.Log.Info("listGatewaysForSecret, secret", "namespace", secret.GetNamespace(), "name", secret.GetName())
324+
var gatewayList gatewayv1.GatewayList
325+
if err := r.List(ctx, &gatewayList, client.MatchingFields{
326+
indexer.SecretIndexRef: indexer.GenIndexKey(secret.GetNamespace(), secret.GetName()),
327+
}); err != nil {
328+
r.Log.Error(err, "failed to list gateways")
329+
return nil
330+
}
331+
for _, gateway := range gatewayList.Items {
332+
requests = append(requests, reconcile.Request{
333+
NamespacedName: types.NamespacedName{
334+
Namespace: gateway.GetNamespace(),
335+
Name: gateway.GetName(),
336+
},
337+
})
338+
}
339+
r.Log.Info("listGatewaysForSecret", "requests", requests)
340+
return requests
341+
}
342+
298343
func (r *GatewayReconciler) processInfrastructure(tctx *provider.TranslateContext, gateway *gatewayv1.Gateway) error {
299344
rk := provider.ResourceKind{
300345
Kind: gateway.Kind,
@@ -316,12 +361,12 @@ func (r *GatewayReconciler) processListenerConfig(tctx *provider.TranslateContex
316361
if ref.Namespace != nil {
317362
ns = string(*ref.Namespace)
318363
}
319-
if ref.Kind != nil && *ref.Kind == gatewayv1.Kind("Secret") {
364+
if ref.Kind != nil && *ref.Kind == "Secret" {
320365
if err := r.Get(context.Background(), client.ObjectKey{
321366
Namespace: ns,
322367
Name: string(ref.Name),
323368
}, &secret); err != nil {
324-
log.Error(err, "failed to get secret", "namespace", ns, "name", string(ref.Name))
369+
log.Error(err, "failed to get secret", "namespace", ns, "name", ref.Name)
325370
SetGatewayListenerConditionProgrammed(gateway, string(listener.Name), false, err.Error())
326371
SetGatewayListenerConditionResolvedRefs(gateway, string(listener.Name), false, err.Error())
327372
break

internal/controller/indexer/indexer.go

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package indexer
22

33
import (
44
"context"
5+
"log"
56

67
networkingv1 "k8s.io/api/networking/v1"
78
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -27,26 +28,19 @@ const (
2728
)
2829

2930
func SetupIndexer(mgr ctrl.Manager) error {
30-
if err := setupGatewayIndexer(mgr); err != nil {
31-
return err
32-
}
33-
if err := setupHTTPRouteIndexer(mgr); err != nil {
34-
return err
35-
}
36-
if err := setupIngressIndexer(mgr); err != nil {
37-
return err
38-
}
39-
if err := setupConsumerIndexer(mgr); err != nil {
40-
return err
41-
}
42-
if err := setupBackendTrafficPolicyIndexer(mgr); err != nil {
43-
return err
44-
}
45-
if err := setupIngressClassIndexer(mgr); err != nil {
46-
return err
47-
}
48-
if err := setupGatewayProxyIndexer(mgr); err != nil {
49-
return err
31+
for _, setup := range []func(ctrl.Manager) error{
32+
setupGatewayIndexer,
33+
setupHTTPRouteIndexer,
34+
setupIngressIndexer,
35+
setupConsumerIndexer,
36+
setupBackendTrafficPolicyIndexer,
37+
setupIngressClassIndexer,
38+
setupGatewayProxyIndexer,
39+
setupGatewaySecretIndex,
40+
} {
41+
if err := setup(mgr); err != nil {
42+
return err
43+
}
5044
}
5145
return nil
5246
}
@@ -191,6 +185,15 @@ func setupGatewayProxyIndexer(mgr ctrl.Manager) error {
191185
return nil
192186
}
193187

188+
func setupGatewaySecretIndex(mgr ctrl.Manager) error {
189+
return mgr.GetFieldIndexer().IndexField(
190+
context.Background(),
191+
&gatewayv1.Gateway{},
192+
SecretIndexRef,
193+
GatewaySecretIndexFunc,
194+
)
195+
}
196+
194197
func GatewayProxySecretIndexFunc(rawObj client.Object) []string {
195198
gatewayProxy := rawObj.(*v1alpha1.GatewayProxy)
196199
secretKeys := make([]string, 0)
@@ -310,6 +313,32 @@ func IngressSecretIndexFunc(rawObj client.Object) []string {
310313
return secrets
311314
}
312315

316+
func GatewaySecretIndexFunc(rawObj client.Object) (keys []string) {
317+
gateway := rawObj.(*gatewayv1.Gateway)
318+
var m = make(map[string]struct{})
319+
for _, listener := range gateway.Spec.Listeners {
320+
if listener.TLS == nil || len(listener.TLS.CertificateRefs) == 0 {
321+
continue
322+
}
323+
for _, ref := range listener.TLS.CertificateRefs {
324+
if ref.Kind == nil || *ref.Kind != "Secret" {
325+
continue
326+
}
327+
namespace := gateway.GetNamespace()
328+
if ref.Namespace != nil {
329+
namespace = string(*ref.Namespace)
330+
}
331+
key := GenIndexKey(namespace, string(ref.Name))
332+
if _, ok := m[key]; !ok {
333+
m[key] = struct{}{}
334+
keys = append(keys, key)
335+
}
336+
}
337+
}
338+
log.Printf("GatewaySecretIndexFunc keys: %v", keys)
339+
return keys
340+
}
341+
313342
func GenIndexKeyWithGK(group, kind, namespace, name string) string {
314343
gvk := schema.GroupKind{
315344
Group: group,

internal/controller/utils.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ package controller
33
import (
44
"context"
55
"fmt"
6+
"path"
7+
"reflect"
68
"strings"
79

8-
"github.com/api7/gopkg/pkg/log"
910
"github.com/samber/lo"
1011
"go.uber.org/zap"
1112
corev1 "k8s.io/api/core/v1"
@@ -17,6 +18,8 @@ import (
1718
"sigs.k8s.io/controller-runtime/pkg/reconcile"
1819
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
1920

21+
"github.com/api7/gopkg/pkg/log"
22+
2023
"github.com/api7/api7-ingress-controller/api/v1alpha1"
2124
"github.com/api7/api7-ingress-controller/internal/controller/config"
2225
"github.com/api7/api7-ingress-controller/internal/provider"
@@ -839,3 +842,14 @@ func ProcessGatewayProxy(r client.Client, tctx *provider.TranslateContext, gatew
839842

840843
return nil
841844
}
845+
846+
// FullTypeName returns the fully qualified name of the type of the given value.
847+
func FullTypeName(a any) string {
848+
typeOf := reflect.TypeOf(a)
849+
pkgPath := typeOf.PkgPath()
850+
name := typeOf.String()
851+
if typeOf.Kind() == reflect.Ptr {
852+
pkgPath = typeOf.Elem().PkgPath()
853+
}
854+
return path.Join(path.Dir(pkgPath), name)
855+
}

test/e2e/gatewayapi/gateway.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ spec:
4848
`
4949

5050
Context("Gateway", func() {
51-
var defautlGatewayClass = `
51+
var defaultGatewayClass = `
5252
apiVersion: gateway.networking.k8s.io/v1
5353
kind: GatewayClass
5454
metadata:
@@ -57,7 +57,7 @@ spec:
5757
controllerName: "apisix.apache.org/api7-ingress-controller"
5858
`
5959

60-
var defautlGateway = `
60+
var defaultGateway = `
6161
apiVersion: gateway.networking.k8s.io/v1
6262
kind: Gateway
6363
metadata:
@@ -101,7 +101,7 @@ spec:
101101
time.Sleep(5 * time.Second)
102102

103103
By("create GatewayClass")
104-
err = s.CreateResourceFromStringWithNamespace(defautlGatewayClass, "")
104+
err = s.CreateResourceFromStringWithNamespace(defaultGatewayClass, "")
105105
Expect(err).NotTo(HaveOccurred(), "creating GatewayClass")
106106
time.Sleep(5 * time.Second)
107107

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

114114
By("create Gateway")
115-
err = s.CreateResourceFromStringWithNamespace(defautlGateway, s.CurrentNamespace())
115+
err = s.CreateResourceFromStringWithNamespace(defaultGateway, s.CurrentNamespace())
116116
Expect(err).NotTo(HaveOccurred(), "creating Gateway")
117117
time.Sleep(5 * time.Second)
118118

@@ -196,7 +196,7 @@ spec:
196196
})
197197

198198
Context("Gateway SSL with and without hostname", func() {
199-
It("Check if SSL resource was created", func() {
199+
FIt("Check if SSL resource was created and updated", func() {
200200
By("create GatewayProxy")
201201
gatewayProxy := fmt.Sprintf(gatewayProxyYaml, framework.DashboardTLSEndpoint, s.AdminKey())
202202
err := s.CreateResourceFromString(gatewayProxy)
@@ -266,6 +266,18 @@ spec:
266266
assert.Len(GinkgoT(), tls, 1, "tls number not expect")
267267
assert.Equal(GinkgoT(), Cert, tls[0].Cert, "tls cert not expect")
268268
assert.Equal(GinkgoT(), tls[0].Labels["k8s/controller-name"], "apisix.apache.org/api7-ingress-controller")
269+
270+
By("update secret")
271+
err = s.NewKubeTlsSecret(secretName, framework.TestCert, framework.TestKey)
272+
Expect(err).NotTo(HaveOccurred(), "update secret")
273+
Eventually(func() string {
274+
tls, err := s.DefaultDataplaneResource().SSL().List(context.Background())
275+
Expect(err).NotTo(HaveOccurred(), "list ssl from dashboard")
276+
if len(tls) < 1 {
277+
return ""
278+
}
279+
return tls[0].Cert
280+
}).WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(framework.TestCert))
269281
})
270282
})
271283
})

0 commit comments

Comments
 (0)