Skip to content

Commit

Permalink
feat: add support of KongServiceFacade as default Ingress backend (#5282
Browse files Browse the repository at this point in the history
)

Adds support for KongServiceFacade as a default Ingress backend along with tests.
  • Loading branch information
czeslavo authored Dec 5, 2023
1 parent 6eaf587 commit 9bbee3b
Show file tree
Hide file tree
Showing 14 changed files with 515 additions and 77 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ Adding a new version? You'll need three changes:
When installed, it has to be enabled with `ServiceFacade` feature gate.
[#5220](https://github.com/Kong/kubernetes-ingress-controller/pull/5220)
[#5234](https://github.com/Kong/kubernetes-ingress-controller/pull/5234)
[#5282](https://github.com/Kong/kubernetes-ingress-controller/pull/5282)
- Added support for GRPC over HTTP (without TLS) in Gateway API.
[#5128](https://github.com/Kong/kubernetes-ingress-controller/pull/5128)
- Added `-init-cache-sync-duration` CLI flag. This flag configures how long the controller waits for Kubernetes resources to populate at startup before generating the initial Kong configuration. It also fixes a bug that removed the default 5 second wait period.
Expand Down
14 changes: 11 additions & 3 deletions internal/dataplane/translator/ingressrules.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,14 @@ func (ir *ingressRules) populateServices(logger logr.Logger, s store.Storer, fai

// collect all the Kubernetes services configured for the service backends,
// and all annotations with our prefix in use across all services (when applicable).
k8sServices, seenKongAnnotations := getK8sServicesForBackends(logger, s, service.Namespace, service.Backends)
serviceParent := ir.ServiceNameToParent[key]
k8sServices, seenKongAnnotations := getK8sServicesForBackends(
s,
service.Namespace,
service.Backends,
failuresCollector,
serviceParent,
)

// if the Kubernetes services have been deemed invalid, log an error message
// and skip the current service.
Expand Down Expand Up @@ -258,10 +265,11 @@ func (s SNIs) Hosts() []string {
}

func getK8sServicesForBackends(
log logr.Logger,
storer store.Storer,
namespace string,
backends kongstate.ServiceBackends,
failuresCollector *failures.ResourceFailuresCollector,
parent client.Object,
) ([]*corev1.Service, map[string]string) {
// we collect all annotations seen for this group of services so that these
// can be later validated.
Expand All @@ -273,7 +281,7 @@ func getK8sServicesForBackends(
for _, backend := range backends {
k8sService, err := resolveKubernetesServiceForBackend(storer, namespace, backend)
if err != nil {
log.Error(err, "Failed to resolve Kubernetes Service for backend")
failuresCollector.PushResourceFailure(fmt.Sprintf("failed to resolve Kubernetes Service for backend: %s", err), parent)
continue
}
if k8sService != nil {
Expand Down
22 changes: 14 additions & 8 deletions internal/dataplane/translator/ingressrules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package translator
import (
"testing"

"github.com/go-logr/logr"
"github.com/go-logr/zapr"
"github.com/kong/go-kong/kong"
"github.com/samber/lo"
Expand Down Expand Up @@ -252,7 +253,7 @@ func TestGetK8sServicesForBackends(t *testing.T) {
services []*corev1.Service
expectedServices []*corev1.Service
expectedAnnotations map[string]string
expectedLogEntries []string
expectedFailures []string
}{
{
name: "if all backends have a service then all services will be returned and their annotations recorded",
Expand Down Expand Up @@ -333,24 +334,29 @@ func TestGetK8sServicesForBackends(t *testing.T) {
},
}},
expectedAnnotations: map[string]string{},
expectedLogEntries: []string{
"Failed to resolve Kubernetes Service for backend",
expectedFailures: []string{
"failed to resolve Kubernetes Service for backend: failed to fetch Service default/test-service2: Service default/test-service2 not found",
},
},
} {
t.Run(tt.name, func(t *testing.T) {
parent := &netv1.Ingress{
ObjectMeta: metav1.ObjectMeta{Name: "ingress", Namespace: tt.namespace},
TypeMeta: metav1.TypeMeta{Kind: "Ingress", APIVersion: netv1.SchemeGroupVersion.String()},
}
storer, err := store.NewFakeStore(store.FakeObjects{Services: tt.services})
require.NoError(t, err)

core, logs := observer.New(zap.InfoLevel)
logger := zapr.NewLogger(zap.New(core))
failuresCollector := failures.NewResourceFailuresCollector(logr.Discard())

services, annotations := getK8sServicesForBackends(logger, storer, tt.namespace, tt.backends)
services, annotations := getK8sServicesForBackends(storer, tt.namespace, tt.backends, failuresCollector, parent)
assert.Equal(t, tt.expectedServices, services)
assert.Equal(t, tt.expectedAnnotations, annotations)
for i, expectedLogEntry := range tt.expectedLogEntries {
assert.Contains(t, logs.All()[i].Entry.Message, expectedLogEntry)
var collectedFailures []string
for _, failure := range failuresCollector.PopResourceFailures() {
collectedFailures = append(collectedFailures, failure.Message())
}
assert.Equal(t, tt.expectedFailures, collectedFailures)
})
}
}
Expand Down
5 changes: 3 additions & 2 deletions internal/dataplane/translator/subtranslator/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func (i *ingressTranslationIndex) getIngressPathBackend(namespace string, httpIn
}

if resource := httpIngressPath.Backend.Resource; resource != nil {
if !isKongServiceFacade(resource) {
if !IsKongServiceFacade(resource) {
gk := resource.Kind
if resource.APIGroup != nil {
gk = *resource.APIGroup + "/" + gk
Expand All @@ -210,7 +210,8 @@ func (i *ingressTranslationIndex) getIngressPathBackend(namespace string, httpIn
return ingressTranslationMetaBackend{}, fmt.Errorf("no Service or Resource specified for Ingress path")
}

func isKongServiceFacade(resource *corev1.TypedLocalObjectReference) bool {
// IsKongServiceFacade returns true if the given resource reference is a KongServiceFacade.
func IsKongServiceFacade(resource *corev1.TypedLocalObjectReference) bool {
return resource.Kind == incubatorv1alpha1.KongServiceFacadeKind &&
resource.APIGroup != nil && *resource.APIGroup == incubatorv1alpha1.GroupVersion.Group
}
Expand Down

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

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

Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ spec:
name: svc-facade-beta
path: /beta
pathType: Exact
defaultBackend:
resource:
apiGroup: incubator.konghq.com
kind: KongServiceFacade
name: svc-facade-default
---
apiVersion: v1
kind: Service
Expand Down Expand Up @@ -92,6 +97,18 @@ spec:
name: svc
port: 80
---
apiVersion: incubator.konghq.com/v1alpha1
kind: KongServiceFacade
metadata:
annotations:
kubernetes.io/ingress.class: kong
name: svc-facade-default
namespace: default
spec:
backendRef:
name: svc
port: 80
---
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
Expand Down
Loading

0 comments on commit 9bbee3b

Please sign in to comment.