Skip to content

Commit

Permalink
feat: assign Service, Route and Consumer entities stable IDs
Browse files Browse the repository at this point in the history
  • Loading branch information
czeslavo committed Apr 25, 2023
1 parent eb974e7 commit fe72ef5
Show file tree
Hide file tree
Showing 7 changed files with 240 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ Adding a new version? You'll need three changes:
[#3832](https://github.com/Kong/kubernetes-ingress-controller/pull/3832)
- Added license agent for Konnect-managed instances.
[#3883](https://github.com/Kong/kubernetes-ingress-controller/pull/3883)
- `Service`, `Route` and `Consumer` Kong entities now get assigned deterministic
IDs based on their unique properties (name, username, etc.) instead of random
UUIDs.
[#3933](https://github.com/Kong/kubernetes-ingress-controller/pull/3933)

### Fixed

Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ require (
github.com/google/go-cmp v0.5.9
github.com/google/uuid v1.3.0
github.com/kong/deck v1.20.0
github.com/kong/go-kong v0.40.0
github.com/kong/go-kong v0.41.0
github.com/kong/kubernetes-telemetry v0.0.2
github.com/kong/kubernetes-testing-framework v0.30.1
github.com/lithammer/dedent v1.1.0
Expand Down Expand Up @@ -114,7 +114,7 @@ require (
github.com/hashicorp/go-retryablehttp v0.7.2 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/imdario/mergo v0.3.15 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSo
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
Expand Down Expand Up @@ -512,6 +513,8 @@ github.com/kong/deck v1.20.0 h1:q8+8VBnvv0O+9mYjcPdJP5prG3KzbvR4XfePwkTx+Zc=
github.com/kong/deck v1.20.0/go.mod h1:yJWEu6/xnYiaNBg2vP4EsYLtbt33J67Zsolye3JpJmI=
github.com/kong/go-kong v0.40.0 h1:6rd70L4GbPz90j3ey+wjHd4aC21uFgbqsoASJhbcbdU=
github.com/kong/go-kong v0.40.0/go.mod h1:t3siZEEGBB3FA5EQv9CL5EcaiogPTG0A175VQ6KvEHE=
github.com/kong/go-kong v0.41.0 h1:0rn+Haf8wfT0VWFVjQPNETLju5ZuNhfbrHYyjpliDBU=
github.com/kong/go-kong v0.41.0/go.mod h1:S/Mx/ZjgwsREPcpMXgCFt5wX7LBpyFlTKENri7E3KTg=
github.com/kong/kubernetes-telemetry v0.0.2 h1:ZLoctQzvo0onCxbMgFMGsIGu6qAXWaMrd4o5Rv//C68=
github.com/kong/kubernetes-telemetry v0.0.2/go.mod h1:lOeCASSR93hssoiOI2HUHoMFLffo/4lLsk74pIqMcyo=
github.com/kong/kubernetes-testing-framework v0.30.1 h1:FZCThCgf2xOi/pUbSzd5hW1ghUnZYihmvy9a3DHMRAE=
Expand Down
23 changes: 23 additions & 0 deletions internal/dataplane/kongstate/kongstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,26 @@ func globalPlugins(log logrus.FieldLogger, s store.Storer) ([]Plugin, error) {
func (ks *KongState) FillPlugins(log logrus.FieldLogger, s store.Storer) {
ks.Plugins = buildPlugins(log, s, ks.getPluginRelations())
}

func (ks *KongState) FillIDs(logger logrus.FieldLogger) {
for svcIndex, svc := range ks.Services {
if err := svc.FillID(); err != nil {
logger.WithError(err).Errorf("failed to fill ID for service %s", *svc.Name)
}
ks.Services[svcIndex] = svc

for routeIndex, route := range svc.Routes {
if err := route.FillID(); err != nil {
logger.WithError(err).Errorf("failed to fill ID for route %s", *route.Name)
}
ks.Services[svcIndex].Routes[routeIndex] = route
}
}

for consumerIndex, consumer := range ks.Consumers {
if err := consumer.FillID(); err != nil {
logger.WithError(err).Errorf("failed to fill ID for consumer %s", *consumer.Username)
}
ks.Consumers[consumerIndex] = consumer
}
}
119 changes: 119 additions & 0 deletions internal/dataplane/kongstate/kongstate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/kong/go-kong/kong"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

Expand Down Expand Up @@ -396,3 +397,121 @@ func TestFillConsumersAndCredentials(t *testing.T) {
assert.Equal(t, want.Consumers[0].Oauth2Creds[0].RedirectURIs, state.Consumers[0].Oauth2Creds[0].RedirectURIs)
})
}

func TestKongState_FillIDs(t *testing.T) {
testCases := []struct {
name string
state KongState
expect func(t *testing.T, s KongState)
}{
{
name: "fills service IDs",
state: KongState{
Services: []Service{
{
Service: kong.Service{
Name: kong.String("service.foo"),
},
},
{
Service: kong.Service{
Name: kong.String("service.bar"),
},
},
},
},
expect: func(t *testing.T, s KongState) {
require.NotEmpty(t, s.Services[0].ID)
require.NotEmpty(t, s.Services[1].ID)
},
},
{
name: "fills route IDs",
state: KongState{
Services: []Service{
{
Service: kong.Service{
Name: kong.String("service.foo"),
},
Routes: []Route{
{
Route: kong.Route{
Name: kong.String("route.foo"),
},
},
{
Route: kong.Route{
Name: kong.String("route.bar"),
},
},
},
},
},
},
expect: func(t *testing.T, s KongState) {
require.NotEmpty(t, s.Services[0].ID)
require.NotEmpty(t, s.Services[0].Routes[0].ID)
require.NotEmpty(t, s.Services[0].Routes[1].ID)
},
},
{
name: "fills consumer IDs",
state: KongState{
Consumers: []Consumer{
{
Consumer: kong.Consumer{
Username: kong.String("user.foo"),
},
},
{
Consumer: kong.Consumer{
Username: kong.String("user.bar"),
},
},
},
},
expect: func(t *testing.T, s KongState) {
require.NotEmpty(t, s.Consumers[0].ID)
require.NotEmpty(t, s.Consumers[1].ID)
},
},
{
name: "fills services, routes, and consumer IDs",
state: KongState{
Services: []Service{
{
Service: kong.Service{
Name: kong.String("service.foo"),
},
Routes: []Route{
{
Route: kong.Route{
Name: kong.String("route.bar"),
},
},
},
},
},
Consumers: []Consumer{
{
Consumer: kong.Consumer{
Username: kong.String("user.baz"),
},
},
},
},
expect: func(t *testing.T, s KongState) {
require.NotEmpty(t, s.Services[0].ID)
require.NotEmpty(t, s.Services[0].Routes[0].ID)
require.NotEmpty(t, s.Consumers[0].ID)
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
tc.state.FillIDs(logrus.New())
tc.expect(t, tc.state)
})
}
}
3 changes: 3 additions & 0 deletions internal/dataplane/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ func (p *Parser) Build() (*kongstate.KongState, []failures.ResourceFailure) {
result.Licenses = append(result.Licenses, *p.license)
}

// generate IDs for Kong entities
result.FillIDs(p.logger)

return &result, p.popTranslationFailures()
}

Expand Down
86 changes: 86 additions & 0 deletions internal/dataplane/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4928,6 +4928,92 @@ func TestCertificate(t *testing.T) {
})
}

func TestParser_FillsEntitiesIDs(t *testing.T) {
s, err := store.NewFakeStore(store.FakeObjects{
Services: []*corev1.Service{
{
ObjectMeta: metav1.ObjectMeta{
Name: "svc.foo",
Namespace: "ns",
},
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{
{
Name: "foo",
Port: 80,
},
},
},
},
},
IngressesV1: []*netv1.Ingress{
{
ObjectMeta: metav1.ObjectMeta{
Name: "ingress.foo",
Namespace: "ns",
Annotations: map[string]string{
annotations.IngressClassKey: annotations.DefaultIngressClass,
},
},
Spec: netv1.IngressSpec{
Rules: []netv1.IngressRule{
{
Host: "foo.com",
IngressRuleValue: netv1.IngressRuleValue{
HTTP: &netv1.HTTPIngressRuleValue{
Paths: []netv1.HTTPIngressPath{
{
Path: "/foo",
Backend: netv1.IngressBackend{
Service: &netv1.IngressServiceBackend{
Name: "svc.foo",
Port: netv1.ServiceBackendPort{
Number: 80,
},
},
},
},
},
},
},
},
},
},
},
},
KongConsumers: []*configurationv1.KongConsumer{
{
ObjectMeta: metav1.ObjectMeta{
Name: "user.foo",
Namespace: "ns",
Annotations: map[string]string{
annotations.IngressClassKey: annotations.DefaultIngressClass,
},
},
Username: "user.foo",
},
},
})
require.NoError(t, err)
p := mustNewParser(t, s)

state, translationFailures := p.Build()
require.Empty(t, translationFailures)
require.NotNil(t, state)

require.Len(t, state.Services, 1)
require.NotNil(t, state.Services[0].ID)
assert.Equal(t, "10157742-edd5-51f6-8141-f21dc8017e87", *state.Services[0].ID, "expected deterministic ID")

require.Len(t, state.Services[0].Routes, 1)
require.NotNil(t, state.Services[0].Routes[0].ID)
assert.Equal(t, "1474bf56-c263-5919-b3e6-e9bc6e4b237f", *state.Services[0].Routes[0].ID, "expected deterministic ID")

require.Len(t, state.Consumers, 1)
require.NotNil(t, state.Consumers[0].ID)
assert.Equal(t, "93c4b796-7cc1-5f86-834c-3bbdf00a806c", *state.Consumers[0].ID, "expected deterministic ID")
}

func mustNewParser(t *testing.T, storer store.Storer) *Parser {
p, err := NewParser(logrus.New(), storer)
require.NoError(t, err)
Expand Down

0 comments on commit fe72ef5

Please sign in to comment.