Skip to content

Commit

Permalink
refactor: use plugin annotation types from kubernetes-configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
pmalek committed Nov 8, 2024
1 parent ef2f1e6 commit aa91d31
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 73 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
module github.com/kong/kubernetes-ingress-controller/v3

go 1.23

toolchain go1.23.2
go 1.23.2

// TODO: this is disabled by FOSSA action doesn't support go 1.21's toolchain clause:
//
Expand Down Expand Up @@ -68,6 +66,8 @@ require (

require github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 // indirect

require github.com/kong/kubernetes-configuration v0.0.42-0.20241108112641-6b1b4bc27468

require (
cloud.google.com/go/auth v0.10.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.5 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ github.com/kong/go-database-reconciler v1.15.0 h1:5F5Zzp2H14aiDmqWUCaU4+LGR/lGnv
github.com/kong/go-database-reconciler v1.15.0/go.mod h1:T5BkBw13PZWub3y2jKAoM7fYD+UmXp2iNqj1YqD0L90=
github.com/kong/go-kong v0.59.1 h1:AJZtyCD+Zyqe/mF/m+x3/qN/GPVxAH7jq9zGJTHRfjc=
github.com/kong/go-kong v0.59.1/go.mod h1:8Vt6HmtgLNgL/7bSwAlz3DIWqBtzG7qEt9+OnMiQOa0=
github.com/kong/kubernetes-configuration v0.0.42-0.20241108112641-6b1b4bc27468 h1:fWl6UyTeEB/hmx5kJxlxZalUZyIXVNFiY0tdCb07jWY=
github.com/kong/kubernetes-configuration v0.0.42-0.20241108112641-6b1b4bc27468/go.mod h1:n4jxy9yTZoSFpBfELB6raVWgsrJTVfhkh1I8W8Uu4Gw=
github.com/kong/kubernetes-telemetry v0.1.7 h1:R4NUpvbF5uZ+5kgSQsIcf/oulRBGQCHsffFRDE4wxV4=
github.com/kong/kubernetes-telemetry v0.1.7/go.mod h1:USy5pcD1+Mm9NtKuz3Pb/rSx71VN76gHCFhdbAB4/lg=
github.com/kong/kubernetes-testing-framework v0.47.2 h1:+2Z9anTpbV/hwNeN+NFQz53BMU+g3QJydkweBp3tULo=
Expand Down
18 changes: 0 additions & 18 deletions internal/annotations/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,24 +138,6 @@ func pluginsFromAnnotations(anns map[string]string) string {
return anns[AnnotationPrefix+PluginsKey]
}

// ExtractKongPluginsFromAnnotations extracts information about Kong
// Plugins configured using konghq.com/plugins annotation.
// This returns a list of KongPlugin resource names that should be applied.
func ExtractKongPluginsFromAnnotations(anns map[string]string) []string {
var kongPluginCRs []string
v := pluginsFromAnnotations(anns)
if v == "" {
return kongPluginCRs
}
for _, kongPlugin := range strings.Split(v, ",") {
s := strings.TrimSpace(kongPlugin)
if s != "" {
kongPluginCRs = append(kongPluginCRs, s)
}
}
return kongPluginCRs
}

type NamespacedKongPlugin k8stypes.NamespacedName

// ExtractNamespacedKongPluginsFromAnnotations extracts a KongPlugin name and optional namespace from an annotation
Expand Down
28 changes: 0 additions & 28 deletions internal/annotations/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,34 +129,6 @@ func TestExtractPath(t *testing.T) {
}
}

func TestExtractKongPluginsFromAnnotations(t *testing.T) {
type args struct {
anns map[string]string
}
tests := []struct {
name string
args args
want []string
}{
{
name: "non-empty",
args: args{
anns: map[string]string{
"konghq.com/plugins": "kp-rl, kp-cors",
},
},
want: []string{"kp-rl", "kp-cors"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ExtractKongPluginsFromAnnotations(tt.args.anns); !reflect.DeepEqual(got, tt.want) {
t.Errorf("ExtractKongPluginsFromAnnotations() = %v, want %v", got, tt.want)
}
})
}
}

func TestExtractNamespacedKongPluginsFromAnnotations(t *testing.T) {
type args struct {
anns map[string]string
Expand Down
3 changes: 2 additions & 1 deletion internal/dataplane/fallback/graph_dependencies_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package fallback
import (
"fmt"

"github.com/kong/kubernetes-configuration/pkg/metadata"
k8stypes "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"

Expand All @@ -14,7 +15,7 @@ import (
// that refers them in its annotations.
func resolveObjectDependenciesPlugin(cache store.CacheStores, obj client.Object) []client.Object {
var dependencies []client.Object
for _, pluginName := range annotations.ExtractKongPluginsFromAnnotations(obj.GetAnnotations()) {
for _, pluginName := range metadata.ExtractPlugins(obj) {
// KongPlugin is tied to a namespace.
if plugin, exists, err := cache.Plugin.GetByKey(
fmt.Sprintf("%s/%s", obj.GetNamespace(), pluginName),
Expand Down
13 changes: 7 additions & 6 deletions internal/dataplane/kongstate/customentity.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import (
"github.com/kong/go-kong/kong"
"github.com/kong/go-kong/kong/custom"
"github.com/samber/lo"
k8stypes "k8s.io/apimachinery/pkg/types"

"github.com/kong/kubernetes-ingress-controller/v3/internal/annotations"
"github.com/kong/kubernetes-ingress-controller/v3/internal/dataplane/failures"
"github.com/kong/kubernetes-ingress-controller/v3/internal/store"
"github.com/kong/kubernetes-ingress-controller/v3/internal/util"
Expand Down Expand Up @@ -302,13 +302,14 @@ func findCustomEntityRelatedPlugin(logger logr.Logger, cacheStore store.Storer,
}

// Extract the plugin key to get the plugin relations.
paretRefNamespace := lo.FromPtrOr(parentRef.Namespace, "")
parentRefNamespace := lo.FromPtrOr(parentRef.Namespace, "")
// if the namespace in parentRef is not same as the namespace of KCE itself, check if the reference is allowed by ReferenceGrant.
if paretRefNamespace != "" && paretRefNamespace != k8sEntity.Namespace {
paretRefNamespace, err := extractReferredPluginNamespace(logger, cacheStore, k8sEntity, annotations.NamespacedKongPlugin{
Namespace: paretRefNamespace,
if parentRefNamespace != "" && parentRefNamespace != k8sEntity.Namespace {
nn := k8stypes.NamespacedName{
Namespace: parentRefNamespace,
Name: parentRef.Name,
})
}
paretRefNamespace, err := extractReferredPluginNamespace(logger, cacheStore, k8sEntity, nn)
if err != nil {
return "", false, err
}
Expand Down
29 changes: 12 additions & 17 deletions internal/dataplane/kongstate/kongstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import (

"github.com/go-logr/logr"
"github.com/kong/go-kong/kong"
"github.com/kong/kubernetes-configuration/pkg/metadata"
"github.com/samber/lo"
corev1 "k8s.io/api/core/v1"
netv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8stypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"sigs.k8s.io/controller-runtime/pkg/client"

Expand Down Expand Up @@ -359,7 +361,7 @@ func (ks *KongState) getPluginRelations(cacheStore store.Storer, log logr.Logger
RouteRelation entityRelationType = iota
ServiceRelation entityRelationType = iota
)
addRelation := func(referrer client.Object, plugin annotations.NamespacedKongPlugin, identifier string, t entityRelationType) {
addRelation := func(referrer client.Object, plugin k8stypes.NamespacedName, identifier string, t entityRelationType) {
// There are 2 types of KongPlugin references: local and remote.
// A local reference is one where the KongPlugin is in the same namespace as the referrer.
// A remote reference is one where the KongPlugin is in a different namespace.
Expand Down Expand Up @@ -396,16 +398,14 @@ func (ks *KongState) getPluginRelations(cacheStore store.Storer, log logr.Logger

for i := range ks.Services {
for _, svc := range ks.Services[i].K8sServices {
pluginList := annotations.ExtractNamespacedKongPluginsFromAnnotations(svc.GetAnnotations())
for _, plugin := range pluginList {
for _, plugin := range metadata.ExtractPluginsNamespacedNames(svc) {
addRelation(svc, plugin, *ks.Services[i].Name, ServiceRelation)
}
}

for j := range ks.Services[i].Routes {
ingress := ks.Services[i].Routes[j].Ingress
pluginList := annotations.ExtractNamespacedKongPluginsFromAnnotations(ingress.Annotations)
for _, plugin := range pluginList {
for _, plugin := range metadata.ExtractPluginsNamespacedNames(ingress) {
// pretend we have a full Ingress struct for reference checks.
// REVIEW: we only need an object to carry type meta and object meta here, maybe we should create some other types of virtual object here?
virtualIngress := netv1.Ingress{
Expand All @@ -422,15 +422,13 @@ func (ks *KongState) getPluginRelations(cacheStore store.Storer, log logr.Logger
}

for _, c := range ks.Consumers {
pluginList := annotations.ExtractNamespacedKongPluginsFromAnnotations(c.K8sKongConsumer.GetAnnotations())
for _, plugin := range pluginList {
for _, plugin := range metadata.ExtractPluginsNamespacedNames(c.K8sKongConsumer) {
addRelation(&c.K8sKongConsumer, plugin, *c.Username, ConsumerRelation)
}
}

for _, cg := range ks.ConsumerGroups {
pluginList := annotations.ExtractNamespacedKongPluginsFromAnnotations(cg.K8sKongConsumerGroup.GetAnnotations())
for _, plugin := range pluginList {
for _, plugin := range metadata.ExtractPluginsNamespacedNames(cg.K8sKongConsumerGroup) {
addRelation(&cg.K8sKongConsumerGroup, plugin, *cg.Name, ConsumerGroupRelation)
}
}
Expand Down Expand Up @@ -755,7 +753,7 @@ func (ks *KongState) getPluginRelatedEntitiesRef(cacheStore store.Storer, log lo
RelatedEntities: map[string]RelatedEntitiesRef{},
RouteAttachedService: map[string]*Service{},
}
addRelation := func(referrer client.Object, plugin annotations.NamespacedKongPlugin, entity any) {
addRelation := func(referrer client.Object, plugin k8stypes.NamespacedName, entity any) {
namespace, err := extractReferredPluginNamespace(log, cacheStore, referrer, plugin)
if err != nil {
log.Error(err, "could not bind requested plugin", "plugin", plugin.Name, "namespace", plugin.Namespace)
Expand All @@ -779,16 +777,14 @@ func (ks *KongState) getPluginRelatedEntitiesRef(cacheStore store.Storer, log lo

for i := range ks.Services {
for _, svc := range ks.Services[i].K8sServices {
pluginList := annotations.ExtractNamespacedKongPluginsFromAnnotations(svc.GetAnnotations())
for _, plugin := range pluginList {
for _, plugin := range metadata.ExtractPluginsNamespacedNames(svc) {
addRelation(svc, plugin, &ks.Services[i])
}
}

for j, r := range ks.Services[i].Routes {
ingress := ks.Services[i].Routes[j].Ingress
pluginList := annotations.ExtractNamespacedKongPluginsFromAnnotations(ingress.Annotations)
for _, plugin := range pluginList {
for _, plugin := range metadata.ExtractPluginsNamespacedNames(ingress) {
// Pretend we have a full Ingress struct for reference checks.
virtualIngress := netv1.Ingress{
// Fill the actual type of the object for reference checks.
Expand All @@ -808,16 +804,15 @@ func (ks *KongState) getPluginRelatedEntitiesRef(cacheStore store.Storer, log lo
}

for i, c := range ks.Consumers {
pluginList := annotations.ExtractNamespacedKongPluginsFromAnnotations(c.K8sKongConsumer.GetAnnotations())
for _, plugin := range pluginList {
for _, plugin := range metadata.ExtractPluginsNamespacedNames(c.K8sKongConsumer) {
addRelation(&c.K8sKongConsumer, plugin, &ks.Consumers[i])
}
}
return pluginRels
}

func extractReferredPluginNamespace(
log logr.Logger, cacheStore store.Storer, referrer client.Object, plugin annotations.NamespacedKongPlugin,
log logr.Logger, cacheStore store.Storer, referrer client.Object, plugin k8stypes.NamespacedName,
) (string, error) {
// There are 2 types of KongPlugin references: local and remote.
// A local reference is one where the KongPlugin is in the same namespace as the referrer.
Expand Down
139 changes: 139 additions & 0 deletions internal/dataplane/kongstate/kongstate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,145 @@ func TestGetPluginRelations(t *testing.T) {
}
}

func BenchmarkGetPluginRelations(b *testing.B) {
ks := KongState{
Consumers: []Consumer{
{
Consumer: kong.Consumer{
Username: kong.String("foo-consumer"),
},
K8sKongConsumer: kongv1.KongConsumer{
ObjectMeta: metav1.ObjectMeta{
Namespace: "ns1",
Annotations: map[string]string{
annotations.AnnotationPrefix + annotations.PluginsKey: "foo,bar",
},
},
},
},
{
Consumer: kong.Consumer{
Username: kong.String("foo-consumer"),
},
K8sKongConsumer: kongv1.KongConsumer{
ObjectMeta: metav1.ObjectMeta{
Namespace: "ns2",
Annotations: map[string]string{
annotations.AnnotationPrefix + annotations.PluginsKey: "foo,bar",
},
},
},
},
{
Consumer: kong.Consumer{
Username: kong.String("bar-consumer"),
},
K8sKongConsumer: kongv1.KongConsumer{
ObjectMeta: metav1.ObjectMeta{
Namespace: "ns1",
Annotations: map[string]string{
annotations.AnnotationPrefix + annotations.PluginsKey: "foobar",
},
},
},
},
},
ConsumerGroups: []ConsumerGroup{
{
ConsumerGroup: kong.ConsumerGroup{
Name: kong.String("foo-consumer-group"),
},
K8sKongConsumerGroup: kongv1beta1.KongConsumerGroup{
ObjectMeta: metav1.ObjectMeta{
Namespace: "ns1",
Annotations: map[string]string{
annotations.AnnotationPrefix + annotations.PluginsKey: "foo,bar",
},
},
},
},
{
ConsumerGroup: kong.ConsumerGroup{
Name: kong.String("foo-consumer-group"),
},
K8sKongConsumerGroup: kongv1beta1.KongConsumerGroup{
ObjectMeta: metav1.ObjectMeta{
Namespace: "ns2",
Annotations: map[string]string{
annotations.AnnotationPrefix + annotations.PluginsKey: "foo,bar",
},
},
},
},
{
ConsumerGroup: kong.ConsumerGroup{
Name: kong.String("bar-consumer-group"),
},
K8sKongConsumerGroup: kongv1beta1.KongConsumerGroup{
ObjectMeta: metav1.ObjectMeta{
Namespace: "ns2",
Annotations: map[string]string{
annotations.AnnotationPrefix + annotations.PluginsKey: "bar,baz",
},
},
},
},
},
Services: []Service{
{
Service: kong.Service{
Name: kong.String("foo-service"),
},
K8sServices: map[string]*corev1.Service{
"foo-service": {
ObjectMeta: metav1.ObjectMeta{
Namespace: "ns1",
Annotations: map[string]string{
annotations.AnnotationPrefix + annotations.PluginsKey: "foo,bar",
},
},
},
},
Routes: []Route{
{
Route: kong.Route{
Name: kong.String("foo-route"),
},
Ingress: util.K8sObjectInfo{
Name: "some-ingress",
Namespace: "ns2",
Annotations: map[string]string{
annotations.AnnotationPrefix + annotations.PluginsKey: "foo,bar",
},
},
},
{
Route: kong.Route{
Name: kong.String("bar-route"),
},
Ingress: util.K8sObjectInfo{
Name: "some-ingress",
Namespace: "ns2",
Annotations: map[string]string{
annotations.AnnotationPrefix + annotations.PluginsKey: "bar,baz",
},
},
},
},
},
},
}

store, err := store.NewFakeStore(store.FakeObjects{})
require.NoError(b, err)
b.ResetTimer()

for i := 0; i < b.N; i++ {
fr := ks.getPluginRelations(store, logr.Discard())
_ = fr
}
}

func TestFillConsumersAndCredentials(t *testing.T) {
secrets := []*corev1.Secret{
{
Expand Down
Loading

0 comments on commit aa91d31

Please sign in to comment.