diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ea8b29dd..3db0ed225 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,8 @@ ### Added +- Log descriptive names when configuring plugins on other entities. + [#662](https://github.com/Kong/deck/pull/662) - Docker images now include `jq` to assist with pre-processing environment substitutions. [#660](https://github.com/Kong/deck/pull/660) diff --git a/file/builder.go b/file/builder.go index 0d0d58c7d..0018c69b4 100644 --- a/file/builder.go +++ b/file/builder.go @@ -201,7 +201,7 @@ func (b *stateBuilder) consumers() { // plugins for the Consumer var plugins []FPlugin for _, p := range c.Plugins { - p.Consumer = &kong.Consumer{ID: kong.String(*c.ID)} + p.Consumer = utils.GetConsumerReference(c.Consumer) plugins = append(plugins, *p) } if err := b.ingestPlugins(plugins); err != nil { @@ -211,7 +211,7 @@ func (b *stateBuilder) consumers() { var keyAuths []kong.KeyAuth for _, cred := range c.KeyAuths { - cred.Consumer = &kong.Consumer{ID: kong.String(*c.ID)} + cred.Consumer = utils.GetConsumerReference(c.Consumer) keyAuths = append(keyAuths, *cred) } if err := b.ingestKeyAuths(keyAuths); err != nil { @@ -221,7 +221,7 @@ func (b *stateBuilder) consumers() { var basicAuths []kong.BasicAuth for _, cred := range c.BasicAuths { - cred.Consumer = &kong.Consumer{ID: kong.String(*c.ID)} + cred.Consumer = utils.GetConsumerReference(c.Consumer) basicAuths = append(basicAuths, *cred) } if err := b.ingestBasicAuths(basicAuths); err != nil { @@ -231,7 +231,7 @@ func (b *stateBuilder) consumers() { var hmacAuths []kong.HMACAuth for _, cred := range c.HMACAuths { - cred.Consumer = &kong.Consumer{ID: kong.String(*c.ID)} + cred.Consumer = utils.GetConsumerReference(c.Consumer) hmacAuths = append(hmacAuths, *cred) } if err := b.ingestHMACAuths(hmacAuths); err != nil { @@ -241,7 +241,7 @@ func (b *stateBuilder) consumers() { var jwtAuths []kong.JWTAuth for _, cred := range c.JWTAuths { - cred.Consumer = &kong.Consumer{ID: kong.String(*c.ID)} + cred.Consumer = utils.GetConsumerReference(c.Consumer) jwtAuths = append(jwtAuths, *cred) } if err := b.ingestJWTAuths(jwtAuths); err != nil { @@ -251,7 +251,7 @@ func (b *stateBuilder) consumers() { var oauth2Creds []kong.Oauth2Credential for _, cred := range c.Oauth2Creds { - cred.Consumer = &kong.Consumer{ID: kong.String(*c.ID)} + cred.Consumer = utils.GetConsumerReference(c.Consumer) oauth2Creds = append(oauth2Creds, *cred) } if err := b.ingestOauth2Creds(oauth2Creds); err != nil { @@ -261,7 +261,7 @@ func (b *stateBuilder) consumers() { var aclGroups []kong.ACLGroup for _, cred := range c.ACLGroups { - cred.Consumer = &kong.Consumer{ID: kong.String(*c.ID)} + cred.Consumer = utils.GetConsumerReference(c.Consumer) aclGroups = append(aclGroups, *cred) } if err := b.ingestACLGroups(aclGroups); err != nil { @@ -271,9 +271,7 @@ func (b *stateBuilder) consumers() { var mtlsAuths []kong.MTLSAuth for _, cred := range c.MTLSAuths { - cred.Consumer = &kong.Consumer{ - ID: kong.String(*c.ID), - } + cred.Consumer = utils.GetConsumerReference(c.Consumer) mtlsAuths = append(mtlsAuths, *cred) } @@ -574,7 +572,7 @@ func (b *stateBuilder) ingestService(s *FService) error { // plugins for the service var plugins []FPlugin for _, p := range s.Plugins { - p.Service = &kong.Service{ID: kong.String(*s.ID)} + p.Service = utils.GetServiceReference(s.Service) plugins = append(plugins, *p) } if err := b.ingestPlugins(plugins); err != nil { @@ -584,7 +582,7 @@ func (b *stateBuilder) ingestService(s *FService) error { // routes for the service for _, r := range s.Routes { r := r - r.Service = &kong.Service{ID: kong.String(*s.ID)} + r.Service = utils.GetServiceReference(s.Service) if err := b.ingestRoute(*r); err != nil { return err } @@ -706,40 +704,40 @@ func (b *stateBuilder) plugins() { c, err := b.intermediate.Consumers.Get(*p.Consumer.ID) if err == state.ErrNotFound { b.err = fmt.Errorf("consumer %v for plugin %v: %w", - *p.Consumer.ID, *p.Name, err) + p.Consumer.FriendlyName(), *p.Name, err) return } else if err != nil { b.err = err return } - p.Consumer = &kong.Consumer{ID: kong.String(*c.ID)} + p.Consumer = utils.GetConsumerReference(c.Consumer) } if p.Service != nil && !utils.Empty(p.Service.ID) { s, err := b.intermediate.Services.Get(*p.Service.ID) if err == state.ErrNotFound { b.err = fmt.Errorf("service %v for plugin %v: %w", - *p.Service.ID, *p.Name, err) + p.Service.FriendlyName(), *p.Name, err) return } else if err != nil { b.err = err return } - p.Service = &kong.Service{ID: kong.String(*s.ID)} + p.Service = utils.GetServiceReference(s.Service) } if p.Route != nil && !utils.Empty(p.Route.ID) { - s, err := b.intermediate.Routes.Get(*p.Route.ID) + r, err := b.intermediate.Routes.Get(*p.Route.ID) if err == state.ErrNotFound { b.err = fmt.Errorf("route %v for plugin %v: %w", - *p.Route.ID, *p.Name, err) + p.Route.FriendlyName(), *p.Name, err) return } else if err != nil { b.err = err return } - p.Route = &kong.Route{ID: kong.String(*s.ID)} + p.Route = utils.GetRouteReference(r.Route) } plugins = append(plugins, p) } @@ -797,7 +795,7 @@ func (b *stateBuilder) ingestRoute(r FRoute) error { // plugins for the route var plugins []FPlugin for _, p := range r.Plugins { - p.Route = &kong.Route{ID: kong.String(*r.ID)} + p.Route = utils.GetRouteReference(r.Route) plugins = append(plugins, *p) } if err := b.ingestPlugins(plugins); err != nil { diff --git a/file/builder_test.go b/file/builder_test.go index 1a7611e1e..92300377d 100644 --- a/file/builder_test.go +++ b/file/builder_test.go @@ -130,7 +130,8 @@ func existingConsumerCredState() *state.KongState { ID: kong.String("5f1ef1ea-a2a5-4a1b-adbb-b0d3434013e5"), Key: kong.String("foo-apikey"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }) @@ -140,7 +141,8 @@ func existingConsumerCredState() *state.KongState { Username: kong.String("basic-username"), Password: kong.String("basic-password"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }) @@ -150,7 +152,8 @@ func existingConsumerCredState() *state.KongState { Key: kong.String("jwt-key"), Secret: kong.String("jwt-secret"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }) @@ -160,7 +163,8 @@ func existingConsumerCredState() *state.KongState { Username: kong.String("hmac-username"), Secret: kong.String("hmac-secret"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }) @@ -169,7 +173,8 @@ func existingConsumerCredState() *state.KongState { ID: kong.String("b7c9352a-775a-4ba5-9869-98e926a3e6cb"), Group: kong.String("foo-group"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }) @@ -179,7 +184,8 @@ func existingConsumerCredState() *state.KongState { ClientID: kong.String("oauth2-clientid"), Name: kong.String("oauth2-name"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }) @@ -188,7 +194,8 @@ func existingConsumerCredState() *state.KongState { ID: kong.String("92f4c829-968b-42af-afd3-f337051508d3"), SubjectName: kong.String("test@example.com"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }) @@ -948,7 +955,8 @@ func Test_stateBuilder_consumers(t *testing.T) { ID: kong.String("dfd79b4d-7642-4b61-ba0c-9f9f0d3ba55b"), Key: kong.String("foo-key"), Consumer: &kong.Consumer{ - ID: kong.String("5b1484f2-5209-49d9-b43e-92ba09dd9d52"), + ID: kong.String("5b1484f2-5209-49d9-b43e-92ba09dd9d52"), + Username: kong.String("foo"), }, }, }, @@ -958,7 +966,8 @@ func Test_stateBuilder_consumers(t *testing.T) { Username: kong.String("basic-username"), Password: kong.String("basic-password"), Consumer: &kong.Consumer{ - ID: kong.String("5b1484f2-5209-49d9-b43e-92ba09dd9d52"), + ID: kong.String("5b1484f2-5209-49d9-b43e-92ba09dd9d52"), + Username: kong.String("foo"), }, }, }, @@ -968,7 +977,8 @@ func Test_stateBuilder_consumers(t *testing.T) { Username: kong.String("hmac-username"), Secret: kong.String("hmac-secret"), Consumer: &kong.Consumer{ - ID: kong.String("5b1484f2-5209-49d9-b43e-92ba09dd9d52"), + ID: kong.String("5b1484f2-5209-49d9-b43e-92ba09dd9d52"), + Username: kong.String("foo"), }, }, }, @@ -978,7 +988,8 @@ func Test_stateBuilder_consumers(t *testing.T) { Key: kong.String("jwt-key"), Secret: kong.String("jwt-secret"), Consumer: &kong.Consumer{ - ID: kong.String("5b1484f2-5209-49d9-b43e-92ba09dd9d52"), + ID: kong.String("5b1484f2-5209-49d9-b43e-92ba09dd9d52"), + Username: kong.String("foo"), }, }, }, @@ -988,7 +999,8 @@ func Test_stateBuilder_consumers(t *testing.T) { ClientID: kong.String("oauth2-clientid"), Name: kong.String("oauth2-name"), Consumer: &kong.Consumer{ - ID: kong.String("5b1484f2-5209-49d9-b43e-92ba09dd9d52"), + ID: kong.String("5b1484f2-5209-49d9-b43e-92ba09dd9d52"), + Username: kong.String("foo"), }, }, }, @@ -997,7 +1009,8 @@ func Test_stateBuilder_consumers(t *testing.T) { ID: kong.String("13dd1aac-04ce-4ea2-877c-5579cfa2c78e"), Group: kong.String("foo-group"), Consumer: &kong.Consumer{ - ID: kong.String("5b1484f2-5209-49d9-b43e-92ba09dd9d52"), + ID: kong.String("5b1484f2-5209-49d9-b43e-92ba09dd9d52"), + Username: kong.String("foo"), }, }, }, @@ -1094,7 +1107,8 @@ func Test_stateBuilder_consumers(t *testing.T) { ID: kong.String("5f1ef1ea-a2a5-4a1b-adbb-b0d3434013e5"), Key: kong.String("foo-apikey"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }, @@ -1104,7 +1118,8 @@ func Test_stateBuilder_consumers(t *testing.T) { Username: kong.String("basic-username"), Password: kong.String("basic-password"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }, @@ -1114,7 +1129,8 @@ func Test_stateBuilder_consumers(t *testing.T) { Username: kong.String("hmac-username"), Secret: kong.String("hmac-secret"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }, @@ -1124,7 +1140,8 @@ func Test_stateBuilder_consumers(t *testing.T) { Key: kong.String("jwt-key"), Secret: kong.String("jwt-secret"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }, @@ -1134,7 +1151,8 @@ func Test_stateBuilder_consumers(t *testing.T) { ClientID: kong.String("oauth2-clientid"), Name: kong.String("oauth2-name"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }, @@ -1143,7 +1161,8 @@ func Test_stateBuilder_consumers(t *testing.T) { ID: kong.String("b7c9352a-775a-4ba5-9869-98e926a3e6cb"), Group: kong.String("foo-group"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }, @@ -1152,7 +1171,8 @@ func Test_stateBuilder_consumers(t *testing.T) { ID: kong.String("533c259e-bf71-4d77-99d2-97944c70a6a4"), SubjectName: kong.String("test@example.com"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }, @@ -1226,7 +1246,8 @@ func Test_stateBuilder_consumers(t *testing.T) { ID: kong.String("5f1ef1ea-a2a5-4a1b-adbb-b0d3434013e5"), Key: kong.String("foo-apikey"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }, @@ -1236,7 +1257,8 @@ func Test_stateBuilder_consumers(t *testing.T) { Username: kong.String("basic-username"), Password: kong.String("basic-password"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }, @@ -1246,7 +1268,8 @@ func Test_stateBuilder_consumers(t *testing.T) { Username: kong.String("hmac-username"), Secret: kong.String("hmac-secret"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }, @@ -1256,7 +1279,8 @@ func Test_stateBuilder_consumers(t *testing.T) { Key: kong.String("jwt-key"), Secret: kong.String("jwt-secret"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }, @@ -1266,7 +1290,8 @@ func Test_stateBuilder_consumers(t *testing.T) { ClientID: kong.String("oauth2-clientid"), Name: kong.String("oauth2-name"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }, @@ -1275,7 +1300,8 @@ func Test_stateBuilder_consumers(t *testing.T) { ID: kong.String("b7c9352a-775a-4ba5-9869-98e926a3e6cb"), Group: kong.String("foo-group"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }, @@ -1284,7 +1310,8 @@ func Test_stateBuilder_consumers(t *testing.T) { ID: kong.String("533c259e-bf71-4d77-99d2-97944c70a6a4"), SubjectName: kong.String("test@example.com"), Consumer: &kong.Consumer{ - ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + ID: kong.String("4bfcb11f-c962-4817-83e5-9433cf20b663"), + Username: kong.String("foo"), }, }, }, @@ -2055,7 +2082,8 @@ func Test_stateBuilder(t *testing.T) { StripPath: kong.Bool(false), Protocols: kong.StringSlice("http", "https"), Service: &kong.Service{ - ID: kong.String("538c7f96-b164-4f1b-97bb-9f4bb472e89f"), + ID: kong.String("538c7f96-b164-4f1b-97bb-9f4bb472e89f"), + Name: kong.String("foo-service"), }, }, { @@ -2066,7 +2094,8 @@ func Test_stateBuilder(t *testing.T) { StripPath: kong.Bool(false), Protocols: kong.StringSlice("http", "https"), Service: &kong.Service{ - ID: kong.String("538c7f96-b164-4f1b-97bb-9f4bb472e89f"), + ID: kong.String("538c7f96-b164-4f1b-97bb-9f4bb472e89f"), + Name: kong.String("foo-service"), }, }, { @@ -2077,7 +2106,8 @@ func Test_stateBuilder(t *testing.T) { StripPath: kong.Bool(false), Protocols: kong.StringSlice("http", "https"), Service: &kong.Service{ - ID: kong.String("dfd79b4d-7642-4b61-ba0c-9f9f0d3ba55b"), + ID: kong.String("dfd79b4d-7642-4b61-ba0c-9f9f0d3ba55b"), + Name: kong.String("bar-service"), }, }, { @@ -2088,7 +2118,8 @@ func Test_stateBuilder(t *testing.T) { StripPath: kong.Bool(false), Protocols: kong.StringSlice("http", "https"), Service: &kong.Service{ - ID: kong.String("dfd79b4d-7642-4b61-ba0c-9f9f0d3ba55b"), + ID: kong.String("dfd79b4d-7642-4b61-ba0c-9f9f0d3ba55b"), + Name: kong.String("bar-service"), }, }, { @@ -2099,7 +2130,8 @@ func Test_stateBuilder(t *testing.T) { StripPath: kong.Bool(false), Protocols: kong.StringSlice("http", "https"), Service: &kong.Service{ - ID: kong.String("9e6f82e5-4e74-4e81-a79e-4bbd6fe34cdc"), + ID: kong.String("9e6f82e5-4e74-4e81-a79e-4bbd6fe34cdc"), + Name: kong.String("large-payload-service"), }, RequestBuffering: kong.Bool(false), ResponseBuffering: kong.Bool(false), @@ -2112,7 +2144,8 @@ func Test_stateBuilder(t *testing.T) { StripPath: kong.Bool(false), Protocols: kong.StringSlice("http", "https"), Service: &kong.Service{ - ID: kong.String("9e6f82e5-4e74-4e81-a79e-4bbd6fe34cdc"), + ID: kong.String("9e6f82e5-4e74-4e81-a79e-4bbd6fe34cdc"), + Name: kong.String("large-payload-service"), }, RequestBuffering: kong.Bool(true), ResponseBuffering: kong.Bool(true), @@ -2337,7 +2370,8 @@ func Test_stateBuilder(t *testing.T) { RequestBuffering: kong.Bool(false), PathHandling: kong.String("v0"), Service: &kong.Service{ - ID: kong.String("538c7f96-b164-4f1b-97bb-9f4bb472e89f"), + ID: kong.String("538c7f96-b164-4f1b-97bb-9f4bb472e89f"), + Name: kong.String("foo-service"), }, }, { @@ -2350,7 +2384,8 @@ func Test_stateBuilder(t *testing.T) { RequestBuffering: kong.Bool(false), PathHandling: kong.String("v0"), Service: &kong.Service{ - ID: kong.String("538c7f96-b164-4f1b-97bb-9f4bb472e89f"), + ID: kong.String("538c7f96-b164-4f1b-97bb-9f4bb472e89f"), + Name: kong.String("foo-service"), }, }, { @@ -2363,7 +2398,8 @@ func Test_stateBuilder(t *testing.T) { RequestBuffering: kong.Bool(false), PathHandling: kong.String("v0"), Service: &kong.Service{ - ID: kong.String("dfd79b4d-7642-4b61-ba0c-9f9f0d3ba55b"), + ID: kong.String("dfd79b4d-7642-4b61-ba0c-9f9f0d3ba55b"), + Name: kong.String("bar-service"), }, }, { @@ -2376,7 +2412,8 @@ func Test_stateBuilder(t *testing.T) { RequestBuffering: kong.Bool(false), PathHandling: kong.String("v0"), Service: &kong.Service{ - ID: kong.String("dfd79b4d-7642-4b61-ba0c-9f9f0d3ba55b"), + ID: kong.String("dfd79b4d-7642-4b61-ba0c-9f9f0d3ba55b"), + Name: kong.String("bar-service"), }, }, { @@ -2388,7 +2425,8 @@ func Test_stateBuilder(t *testing.T) { Protocols: kong.StringSlice("http", "https"), PathHandling: kong.String("v0"), Service: &kong.Service{ - ID: kong.String("9e6f82e5-4e74-4e81-a79e-4bbd6fe34cdc"), + ID: kong.String("9e6f82e5-4e74-4e81-a79e-4bbd6fe34cdc"), + Name: kong.String("large-payload-service"), }, RequestBuffering: kong.Bool(false), ResponseBuffering: kong.Bool(false), @@ -2402,7 +2440,8 @@ func Test_stateBuilder(t *testing.T) { Protocols: kong.StringSlice("http", "https"), PathHandling: kong.String("v0"), Service: &kong.Service{ - ID: kong.String("9e6f82e5-4e74-4e81-a79e-4bbd6fe34cdc"), + ID: kong.String("9e6f82e5-4e74-4e81-a79e-4bbd6fe34cdc"), + Name: kong.String("large-payload-service"), }, RequestBuffering: kong.Bool(true), ResponseBuffering: kong.Bool(true), diff --git a/state/builder.go b/state/builder.go index dece99dde..bd03d3f48 100644 --- a/state/builder.go +++ b/state/builder.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/kong/deck/utils" + "github.com/kong/go-kong/kong" ) // Get builds a KongState from a raw representation of Kong. @@ -19,6 +20,42 @@ func Get(raw *utils.KongRawState) (*KongState, error) { return kongState, nil } +func ensureService(kongState *KongState, serviceID string) (bool, *kong.Service, error) { + s, err := kongState.Services.Get(serviceID) + if err != nil { + if err == ErrNotFound { + return false, nil, nil + } + return false, nil, fmt.Errorf("looking up service %q: %w", serviceID, err) + + } + return true, utils.GetServiceReference(s.Service), nil +} + +func ensureRoute(kongState *KongState, routeID string) (bool, *kong.Route, error) { + r, err := kongState.Routes.Get(routeID) + if err != nil { + if err == ErrNotFound { + return false, nil, nil + } + return false, nil, fmt.Errorf("looking up route %q: %w", routeID, err) + + } + return true, utils.GetRouteReference(r.Route), nil +} + +func ensureConsumer(kongState *KongState, consumerID string) (bool, *kong.Consumer, error) { + c, err := kongState.Consumers.Get(consumerID) + if err != nil { + if err == ErrNotFound { + return false, nil, nil + } + return false, nil, fmt.Errorf("looking up consumer %q: %w", consumerID, err) + + } + return true, utils.GetConsumerReference(c.Consumer), nil +} + func buildKong(kongState *KongState, raw *utils.KongRawState) error { for _, s := range raw.Services { err := kongState.Services.Add(Service{Service: *s}) @@ -27,6 +64,15 @@ func buildKong(kongState *KongState, raw *utils.KongRawState) error { } } for _, r := range raw.Routes { + if r.Service != nil && !utils.Empty(r.Service.ID) { + ok, s, err := ensureService(kongState, *r.Service.ID) + if err != nil { + return err + } + if ok { + r.Service = s + } + } err := kongState.Routes.Add(Route{Route: *r}) if err != nil { return fmt.Errorf("inserting route into state: %w", err) @@ -38,103 +84,99 @@ func buildKong(kongState *KongState, raw *utils.KongRawState) error { return fmt.Errorf("inserting consumer into state: %w", err) } } - ensureConsumer := func(consumerID string) (bool, error) { - _, err := kongState.Consumers.Get(consumerID) - if err != nil { - if err == ErrNotFound { - return false, nil - } - return false, fmt.Errorf("looking up consumer %q: %w", consumerID, err) - - } - return true, nil - } for _, cred := range raw.KeyAuths { - ok, err := ensureConsumer(*cred.Consumer.ID) + ok, c, err := ensureConsumer(kongState, *cred.Consumer.ID) if err != nil { return err } if !ok { continue } + cred.Consumer = c err = kongState.KeyAuths.Add(KeyAuth{KeyAuth: *cred}) if err != nil { return fmt.Errorf("inserting key-auth into state: %w", err) } } for _, cred := range raw.HMACAuths { - ok, err := ensureConsumer(*cred.Consumer.ID) + ok, c, err := ensureConsumer(kongState, *cred.Consumer.ID) if err != nil { return err } if !ok { continue } + cred.Consumer = c err = kongState.HMACAuths.Add(HMACAuth{HMACAuth: *cred}) if err != nil { return fmt.Errorf("inserting hmac-auth into state: %w", err) } } for _, cred := range raw.JWTAuths { - ok, err := ensureConsumer(*cred.Consumer.ID) + ok, c, err := ensureConsumer(kongState, *cred.Consumer.ID) if err != nil { return err } if !ok { continue } + cred.Consumer = c err = kongState.JWTAuths.Add(JWTAuth{JWTAuth: *cred}) if err != nil { return fmt.Errorf("inserting jwt into state: %w", err) } } for _, cred := range raw.BasicAuths { - ok, err := ensureConsumer(*cred.Consumer.ID) + ok, c, err := ensureConsumer(kongState, *cred.Consumer.ID) if err != nil { return err } if !ok { continue } + cred.Consumer = c err = kongState.BasicAuths.Add(BasicAuth{BasicAuth: *cred}) if err != nil { return fmt.Errorf("inserting basic-auth into state: %w", err) } } for _, cred := range raw.Oauth2Creds { - ok, err := ensureConsumer(*cred.Consumer.ID) + ok, c, err := ensureConsumer(kongState, *cred.Consumer.ID) if err != nil { return err } if !ok { continue } + cred.Consumer = c err = kongState.Oauth2Creds.Add(Oauth2Credential{Oauth2Credential: *cred}) if err != nil { return fmt.Errorf("inserting oauth2-cred into state: %w", err) } } for _, cred := range raw.ACLGroups { - ok, err := ensureConsumer(*cred.Consumer.ID) + ok, c, err := ensureConsumer(kongState, *cred.Consumer.ID) if err != nil { return err } if !ok { continue } + cred.Consumer = c err = kongState.ACLGroups.Add(ACLGroup{ACLGroup: *cred}) if err != nil { return fmt.Errorf("inserting basic-auth into state: %w", err) } } for _, cred := range raw.MTLSAuths { - ok, err := ensureConsumer(*cred.Consumer.ID) + ok, c, err := ensureConsumer(kongState, *cred.Consumer.ID) if err != nil { return err } if !ok { continue } + cred.Consumer = c err = kongState.MTLSAuths.Add(MTLSAuth{MTLSAuth: *cred}) if err != nil { return fmt.Errorf("inserting mtls-auth into state: %w", err) @@ -177,6 +219,33 @@ func buildKong(kongState *KongState, raw *utils.KongRawState) error { } for _, p := range raw.Plugins { + if p.Service != nil && !utils.Empty(p.Service.ID) { + ok, s, err := ensureService(kongState, *p.Service.ID) + if err != nil { + return err + } + if ok { + p.Service = s + } + } + if p.Route != nil && !utils.Empty(p.Route.ID) { + ok, r, err := ensureRoute(kongState, *p.Route.ID) + if err != nil { + return err + } + if ok { + p.Route = r + } + } + if p.Consumer != nil && !utils.Empty(p.Consumer.ID) { + ok, c, err := ensureConsumer(kongState, *p.Consumer.ID) + if err != nil { + return err + } + if ok { + p.Consumer = c + } + } err := kongState.Plugins.Add(Plugin{Plugin: *p}) if err != nil { return fmt.Errorf("inserting plugins into state: %w", err) diff --git a/state/rbac_endpoint_permission.go b/state/rbac_endpoint_permission.go index 049dc9ec1..2d0c4b1ea 100644 --- a/state/rbac_endpoint_permission.go +++ b/state/rbac_endpoint_permission.go @@ -63,7 +63,7 @@ func (k *RBACEndpointPermissionsCollection) Add(rbacEndpointPermission RBACEndpo defer txn.Abort() var searchBy []string - searchBy = append(searchBy, rbacEndpointPermission.Identifier()) + searchBy = append(searchBy, rbacEndpointPermission.FriendlyName()) _, err := getRBACEndpointPermission(txn, searchBy...) if err == nil { @@ -71,7 +71,7 @@ func (k *RBACEndpointPermissionsCollection) Add(rbacEndpointPermission RBACEndpo } else if err != ErrNotFound { return err } - rbacEndpointPermission.ID = rbacEndpointPermission.Identifier() + rbacEndpointPermission.ID = rbacEndpointPermission.FriendlyName() err = txn.Insert(rbacEndpointPermissionTableName, &rbacEndpointPermission) if err != nil { return err @@ -119,12 +119,12 @@ func (k *RBACEndpointPermissionsCollection) Update(rbacEndpointPermission RBACEn txn := k.db.Txn(true) defer txn.Abort() - err := deleteRBACEndpointPermission(txn, rbacEndpointPermission.Identifier()) + err := deleteRBACEndpointPermission(txn, rbacEndpointPermission.FriendlyName()) if err != nil { return err } - rbacEndpointPermission.ID = rbacEndpointPermission.Identifier() + rbacEndpointPermission.ID = rbacEndpointPermission.FriendlyName() err = txn.Insert(rbacEndpointPermissionTableName, &rbacEndpointPermission) if err != nil { return err @@ -139,7 +139,7 @@ func deleteRBACEndpointPermission(txn *memdb.Txn, nameOrID string) error { if err != nil { return err } - rbacEndpointPermission.ID = rbacEndpointPermission.Identifier() + rbacEndpointPermission.ID = rbacEndpointPermission.FriendlyName() err = txn.Delete(rbacEndpointPermissionTableName, rbacEndpointPermission) if err != nil { return err diff --git a/state/rbac_endpoint_permission_test.go b/state/rbac_endpoint_permission_test.go index 1a8c8666f..bb915cd17 100644 --- a/state/rbac_endpoint_permission_test.go +++ b/state/rbac_endpoint_permission_test.go @@ -99,7 +99,7 @@ func TestRBACEndpointPermissionsCollection_Get(t *testing.T) { { name: "gets a rbacEndpointPermission by ID", args: args{ - nameOrID: rbacEndpointPermission1.Identifier(), + nameOrID: rbacEndpointPermission1.FriendlyName(), }, want: &rbacEndpointPermission1, wantErr: false, @@ -107,7 +107,7 @@ func TestRBACEndpointPermissionsCollection_Get(t *testing.T) { { name: "gets a rbacEndpointPermission by Name", args: args{ - nameOrID: rbacEndpointPermission2.Identifier(), + nameOrID: rbacEndpointPermission2.FriendlyName(), }, want: &rbacEndpointPermission2, wantErr: false, @@ -215,7 +215,7 @@ func TestRBACEndpointPermissionsCollection_Update(t *testing.T) { t.Errorf("RBACEndpointPermissionsCollection.Update() error = %v, wantErr %v", err, tt.wantErr) } if !tt.wantErr { - got, _ := k.Get(tt.updatedRBACEndpointPermission.Identifier()) + got, _ := k.Get(tt.updatedRBACEndpointPermission.FriendlyName()) if !reflect.DeepEqual(got, tt.updatedRBACEndpointPermission) { t.Errorf("update rbacEndpointPermission, got = %#v, want %#v", got, tt.updatedRBACEndpointPermission) @@ -239,14 +239,14 @@ func TestRBACEndpointPermissionDelete(t *testing.T) { err := collection.Add(rbacEndpointPermission) assert.Nil(err) - re, err := collection.Get(rbacEndpointPermission.Identifier()) + re, err := collection.Get(rbacEndpointPermission.FriendlyName()) assert.Nil(err) assert.NotNil(re) - err = collection.Delete(re.Identifier()) + err = collection.Delete(re.FriendlyName()) assert.Nil(err) - err = collection.Delete(re.Identifier()) + err = collection.Delete(re.FriendlyName()) assert.NotNil(err) } diff --git a/state/types.go b/state/types.go index f0be64f39..01e12d91b 100644 --- a/state/types.go +++ b/state/types.go @@ -81,7 +81,7 @@ func (s1 *Service) Identifier() string { // Console returns an entity's identity in a human // readable string. func (s1 *Service) Console() string { - return s1.Identifier() + return s1.FriendlyName() } // Equal returns true if s1 and s2 are equal. @@ -135,7 +135,7 @@ func (r1 *Route) Identifier() string { // Console returns an entity's identity in a human // readable string. func (r1 *Route) Console() string { - return r1.Identifier() + return r1.FriendlyName() } // Equal returns true if r1 and r2 are equal. @@ -171,6 +171,13 @@ func (r1 *Route) EqualWithOpts(r2 *Route, ignoreID, r1Copy.Service = nil r2Copy.Service = nil } + + if r1Copy.Service != nil { + r1Copy.Service.Name = nil + } + if r2Copy.Service != nil { + r2Copy.Service.Name = nil + } return reflect.DeepEqual(r1Copy, r2Copy) } @@ -192,7 +199,7 @@ func (u1 *Upstream) Identifier() string { // Console returns an entity's identity in a human // readable string. func (u1 *Upstream) Console() string { - return u1.Identifier() + return u1.FriendlyName() } // Equal returns true if u1 and u2 are equal. @@ -241,14 +248,9 @@ func (t1 *Target) Identifier() string { // Console returns an entity's identity in a human // readable string. func (t1 *Target) Console() string { - res := t1.Identifier() + res := t1.FriendlyName() if t1.Upstream != nil { - if t1.Upstream.ID != nil { - res = res + " for upstream " + *t1.Upstream.ID - } - if t1.Upstream.Name != nil { - res = res + " for upstream " + *t1.Upstream.Name - } + res = res + " for upstream " + t1.Upstream.FriendlyName() } return res } @@ -305,7 +307,7 @@ func (c1 *Certificate) Identifier() string { // Console returns an entity's identity in a human // readable string. func (c1 *Certificate) Console() string { - return c1.Identifier() + return c1.FriendlyName() } // Equal returns true if c1 and c2 are equal. @@ -343,12 +345,6 @@ type SNI struct { Meta } -// Equal returns true if s1 and s2 are equal. -// TODO add compare array without position -func (s1 *SNI) Equal(s2 *SNI) bool { - return s1.EqualWithOpts(s2, false, false, false) -} - // Identifier returns the endpoint key name or ID. func (s1 *SNI) Identifier() string { if s1.Name != nil { @@ -357,10 +353,16 @@ func (s1 *SNI) Identifier() string { return *s1.ID } +// Equal returns true if s1 and s2 are equal. +// TODO add compare array without position +func (s1 *SNI) Equal(s2 *SNI) bool { + return s1.EqualWithOpts(s2, false, false, false) +} + // Console returns an entity's identity in a human // readable string. func (s1 *SNI) Console() string { - return s1.Identifier() + return s1.FriendlyName() } // EqualWithOpts returns true if s1 and s2 are equal. @@ -415,13 +417,13 @@ func (p1 *Plugin) Console() string { } associations := []string{} if p1.Service != nil { - associations = append(associations, "service "+*p1.Service.ID) + associations = append(associations, "service "+p1.Service.FriendlyName()) } if p1.Route != nil { - associations = append(associations, "route "+*p1.Route.ID) + associations = append(associations, "route "+p1.Route.FriendlyName()) } if p1.Consumer != nil { - associations = append(associations, "consumer "+*p1.Consumer.ID) + associations = append(associations, "consumer "+p1.Consumer.FriendlyName()) } if len(associations) > 0 { res += "for " @@ -469,6 +471,25 @@ func (p1 *Plugin) EqualWithOpts(p2 *Plugin, ignoreID, p2Copy.Route = nil p2Copy.Consumer = nil } + + if p1Copy.Service != nil { + p1Copy.Service.Name = nil + } + if p2Copy.Service != nil { + p2Copy.Service.Name = nil + } + if p1Copy.Route != nil { + p1Copy.Route.Name = nil + } + if p2Copy.Route != nil { + p2Copy.Route.Name = nil + } + if p1Copy.Consumer != nil { + p1Copy.Consumer.Username = nil + } + if p2Copy.Consumer != nil { + p2Copy.Consumer.Username = nil + } return reflect.DeepEqual(p1Copy, p2Copy) } @@ -490,7 +511,7 @@ func (c1 *Consumer) Identifier() string { // Console returns an entity's identity in a human // readable string. func (c1 *Consumer) Console() string { - return c1.Identifier() + return c1.FriendlyName() } // Equal returns true if c1 and c2 are equal. @@ -523,11 +544,9 @@ func (c1 *Consumer) EqualWithOpts(c2 *Consumer, func forConsumerString(c *kong.Consumer) string { if c != nil { - if c.Username != nil { - return " for consumer " + *c.Username - } - if c.ID != nil { - return " for consumer " + *c.ID + friendlyName := c.FriendlyName() + if friendlyName != "" { + return " for consumer " + friendlyName } } return "" @@ -585,6 +604,12 @@ func (k1 *KeyAuth) EqualWithOpts(k2 *KeyAuth, ignoreID, k1Copy.Consumer = nil k2Copy.Consumer = nil } + if k1Copy.Consumer != nil { + k1Copy.Consumer.Username = nil + } + if k2Copy.Consumer != nil { + k2Copy.Consumer.Username = nil + } return reflect.DeepEqual(k1Copy, k2Copy) } @@ -657,6 +682,12 @@ func (h1 *HMACAuth) EqualWithOpts(h2 *HMACAuth, ignoreID, h1Copy.Consumer = nil h2Copy.Consumer = nil } + if h1Copy.Consumer != nil { + h1Copy.Consumer.Username = nil + } + if h2Copy.Consumer != nil { + h2Copy.Consumer.Username = nil + } return reflect.DeepEqual(h1Copy, h2Copy) } @@ -729,6 +760,12 @@ func (j1 *JWTAuth) EqualWithOpts(j2 *JWTAuth, ignoreID, j1Copy.Consumer = nil j2Copy.Consumer = nil } + if j1Copy.Consumer != nil { + j1Copy.Consumer.Username = nil + } + if j2Copy.Consumer != nil { + j2Copy.Consumer.Username = nil + } return reflect.DeepEqual(j1Copy, j2Copy) } @@ -805,6 +842,12 @@ func (b1 *BasicAuth) EqualWithOpts(b2 *BasicAuth, ignoreID, b1Copy.Consumer = nil b2Copy.Consumer = nil } + if b1Copy.Consumer != nil { + b1Copy.Consumer.Username = nil + } + if b2Copy.Consumer != nil { + b2Copy.Consumer.Username = nil + } return reflect.DeepEqual(b1Copy, b2Copy) } @@ -877,6 +920,12 @@ func (b1 *ACLGroup) EqualWithOpts(b2 *ACLGroup, ignoreID, b1Copy.Consumer = nil b2Copy.Consumer = nil } + if b1Copy.Consumer != nil { + b1Copy.Consumer.Username = nil + } + if b2Copy.Consumer != nil { + b2Copy.Consumer.Username = nil + } return reflect.DeepEqual(b1Copy, b2Copy) } @@ -899,7 +948,7 @@ func (c1 *CACertificate) Identifier() string { // Console returns an entity's identity in a human // readable string. func (c1 *CACertificate) Console() string { - return c1.Identifier() + return c1.FriendlyName() } // Equal returns true if c1 and c2 are equal. @@ -972,6 +1021,12 @@ func (k1 *Oauth2Credential) EqualWithOpts(k2 *Oauth2Credential, ignoreID, k1Copy.Consumer = nil k2Copy.Consumer = nil } + if k1Copy.Consumer != nil { + k1Copy.Consumer.Username = nil + } + if k2Copy.Consumer != nil { + k2Copy.Consumer.Username = nil + } return reflect.DeepEqual(k1Copy, k2Copy) } @@ -1044,6 +1099,12 @@ func (b1 *MTLSAuth) EqualWithOpts(b2 *MTLSAuth, ignoreID, b1Copy.Consumer = nil b2Copy.Consumer = nil } + if b1Copy.Consumer != nil { + b1Copy.Consumer.Username = nil + } + if b2Copy.Consumer != nil { + b2Copy.Consumer.Username = nil + } return reflect.DeepEqual(b1Copy, b2Copy) } @@ -1065,7 +1126,7 @@ func (r1 *RBACRole) Identifier() string { // Console returns an entity's identity in a human // readable string. func (r1 *RBACRole) Console() string { - return r1.Identifier() + return r1.FriendlyName() } // Equal returns true if r1 and r2 are equal. @@ -1114,7 +1175,7 @@ func (r1 *RBACEndpointPermission) Identifier() string { // Console returns an entity's identity in a human // readable string. func (r1 *RBACEndpointPermission) Console() string { - return r1.Identifier() + return r1.FriendlyName() } // Equal returns true if r1 and r2 are equal. diff --git a/tests/integration/sync_test.go b/tests/integration/sync_test.go index 55bcac9c3..414ad22ea 100644 --- a/tests/integration/sync_test.go +++ b/tests/integration/sync_test.go @@ -15,6 +15,7 @@ var ( // missing Enable svc1 = []*kong.Service{ { + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), Name: kong.String("svc1"), ConnectTimeout: kong.Int(60000), Host: kong.String("mockbin.org"), @@ -30,6 +31,7 @@ var ( // latest svc1_207 = []*kong.Service{ { + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), Name: kong.String("svc1"), ConnectTimeout: kong.Int(60000), Host: kong.String("mockbin.org"), @@ -46,6 +48,7 @@ var ( // missing RequestBuffering, ResponseBuffering, Service, PathHandling route1_143 = []*kong.Route{ { + ID: kong.String("87b6a97e-f3f7-4c47-857a-7464cb9e202b"), Name: kong.String("r1"), Paths: []*string{kong.String("/r1")}, PreserveHost: kong.Bool(false), @@ -60,6 +63,7 @@ var ( // PathHandling set to v1 route1_151 = []*kong.Route{ { + ID: kong.String("87b6a97e-f3f7-4c47-857a-7464cb9e202b"), Name: kong.String("r1"), Paths: []*string{kong.String("/r1")}, PathHandling: kong.String("v1"), @@ -69,7 +73,7 @@ var ( StripPath: kong.Bool(true), HTTPSRedirectStatusCode: kong.Int(301), Service: &kong.Service{ - ID: kong.String("6d4e90fa-cb78-4607-8c4f-f12245ba8b59"), + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), }, }, } @@ -77,6 +81,7 @@ var ( // missing RequestBuffering, ResponseBuffering route1_205_214 = []*kong.Route{ { + ID: kong.String("87b6a97e-f3f7-4c47-857a-7464cb9e202b"), Name: kong.String("r1"), Paths: []*string{kong.String("/r1")}, PathHandling: kong.String("v0"), @@ -86,7 +91,7 @@ var ( StripPath: kong.Bool(true), HTTPSRedirectStatusCode: kong.Int(301), Service: &kong.Service{ - ID: kong.String("6d4e90fa-cb78-4607-8c4f-f12245ba8b59"), + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), }, }, } @@ -94,6 +99,7 @@ var ( // latest route1_20x = []*kong.Route{ { + ID: kong.String("87b6a97e-f3f7-4c47-857a-7464cb9e202b"), Name: kong.String("r1"), Paths: []*string{kong.String("/r1")}, PathHandling: kong.String("v0"), @@ -105,7 +111,7 @@ var ( RequestBuffering: kong.Bool(true), ResponseBuffering: kong.Bool(true), Service: &kong.Service{ - ID: kong.String("8076db2-28b6-423b-ba39-a797193017f7"), + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), }, }, } @@ -147,6 +153,77 @@ var ( }, } + plugin_on_entities = []*kong.Plugin{ + { + Name: kong.String("prometheus"), + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Enabled: kong.Bool(true), + Config: kong.Configuration{ + "per_consumer": false, + }, + Service: &kong.Service{ + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), + }, + }, + { + Name: kong.String("prometheus"), + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Enabled: kong.Bool(true), + Config: kong.Configuration{ + "per_consumer": false, + }, + Route: &kong.Route{ + ID: kong.String("87b6a97e-f3f7-4c47-857a-7464cb9e202b"), + }, + }, + { + Name: kong.String("rate-limiting"), + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Enabled: kong.Bool(true), + Config: kong.Configuration{ + "day": nil, + "fault_tolerant": true, + "header_name": nil, + "hide_client_headers": false, + "hour": float64(10), + "limit_by": "consumer", + "minute": nil, + "month": nil, + "path": nil, + "policy": "cluster", + "redis_username": nil, + "redis_database": float64(0), + "redis_host": nil, + "redis_password": nil, + "redis_port": float64(6379), + "redis_server_name": nil, + "redis_ssl": false, + "redis_ssl_verify": false, + "redis_timeout": float64(2000), + "second": nil, + "year": nil, + }, + Consumer: &kong.Consumer{ + ID: kong.String("d2965b9b-0608-4458-a9f8-0b93d88d03b8"), + }, + }, + } + upstream = []*kong.Upstream{ { Name: kong.String("upstream1"), @@ -253,6 +330,13 @@ var ( Tags: nil, }, } + + consumer = []*kong.Consumer{ + { + Username: kong.String("yolo"), + ID: kong.String("d2965b9b-0608-4458-a9f8-0b93d88d03b8"), + }, + } ) // test scope: @@ -1157,3 +1241,39 @@ func Test_Sync_Create_Route_With_Service_Name_Reference(t *testing.T) { }) } } + +func Test_Sync_PluginsOnEntities(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Errorf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "create plugins on services, routes and consumers", + kongFile: "testdata/sync/xxx-plugins-on-entities/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + Routes: route1_20x, + Plugins: plugin_on_entities, + Consumers: consumer, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + kong.RunWhenKong(t, ">=2.8.0") + teardown := setup(t) + defer teardown(t) + + sync(tc.kongFile) + testKongState(t, client, tc.expectedState, nil) + }) + } +} diff --git a/tests/integration/test_utils.go b/tests/integration/test_utils.go index af5534208..a17a8362e 100644 --- a/tests/integration/test_utils.go +++ b/tests/integration/test_utils.go @@ -43,6 +43,24 @@ func sortSlices(x, y interface{}) bool { yEntity := y.(*kong.Plugin) xName = *xEntity.Name yName = *yEntity.Name + if xEntity.Route != nil { + xName += *xEntity.Route.ID + } + if xEntity.Service != nil { + xName += *xEntity.Service.ID + } + if xEntity.Consumer != nil { + xName += *xEntity.Consumer.ID + } + if yEntity.Route != nil { + yName += *yEntity.Route.ID + } + if yEntity.Service != nil { + yName += *yEntity.Service.ID + } + if yEntity.Consumer != nil { + yName += *yEntity.Consumer.ID + } } return xName < yName } @@ -62,14 +80,15 @@ func testKongState(t *testing.T, client *kong.Client, } opt := []cmp.Option{ - cmpopts.IgnoreFields(kong.Service{}, "ID", "CreatedAt", "UpdatedAt"), - cmpopts.IgnoreFields(kong.Route{}, "ID", "CreatedAt", "UpdatedAt"), + cmpopts.IgnoreFields(kong.Service{}, "CreatedAt", "UpdatedAt"), + cmpopts.IgnoreFields(kong.Route{}, "CreatedAt", "UpdatedAt"), cmpopts.IgnoreFields(kong.Plugin{}, "ID", "CreatedAt"), cmpopts.IgnoreFields(kong.Upstream{}, "ID", "CreatedAt"), cmpopts.IgnoreFields(kong.Target{}, "ID", "CreatedAt"), cmpopts.IgnoreFields(kong.CACertificate{}, "ID", "CreatedAt"), cmpopts.IgnoreFields(kong.RBACEndpointPermission{}, "Role", "CreatedAt"), cmpopts.IgnoreFields(kong.RBACRole{}, "ID", "CreatedAt"), + cmpopts.IgnoreFields(kong.Consumer{}, "CreatedAt"), cmpopts.SortSlices(sortSlices), cmpopts.SortSlices(func(a, b *string) bool { return *a < *b }), cmpopts.EquateEmpty(), diff --git a/tests/integration/testdata/sync/002-create-services-and-routes/kong.yaml b/tests/integration/testdata/sync/002-create-services-and-routes/kong.yaml index 30aa9d372..da79fdfed 100644 --- a/tests/integration/testdata/sync/002-create-services-and-routes/kong.yaml +++ b/tests/integration/testdata/sync/002-create-services-and-routes/kong.yaml @@ -10,6 +10,7 @@ services: retries: 5 routes: - name: r1 + id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b https_redirect_status_code: 301 paths: - /r1 \ No newline at end of file diff --git a/tests/integration/testdata/sync/003-create-a-plugin/kong.yaml b/tests/integration/testdata/sync/003-create-a-plugin/kong.yaml index e5f8a6084..cd66122cb 100644 --- a/tests/integration/testdata/sync/003-create-a-plugin/kong.yaml +++ b/tests/integration/testdata/sync/003-create-a-plugin/kong.yaml @@ -1,6 +1,7 @@ _format_version: "1.1" plugins: -- name: basic-auth +- id: efead952-0a1d-43ec-9794-0ac6abdc7f55 + name: basic-auth config: anonymous: 58076db2-28b6-423b-ba39-a797193017f7 hide_credentials: false diff --git a/tests/integration/testdata/sync/008-create-simple-entities/kong.yaml b/tests/integration/testdata/sync/008-create-simple-entities/kong.yaml index 3a608c25a..bae23a376 100644 --- a/tests/integration/testdata/sync/008-create-simple-entities/kong.yaml +++ b/tests/integration/testdata/sync/008-create-simple-entities/kong.yaml @@ -1,9 +1,11 @@ _format_version: "1.1" services: -- name: svc1 +- id: 58076db2-28b6-423b-ba39-a797193017f7 + name: svc1 host: mockbin.org routes: - - name: r1 + - id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + name: r1 https_redirect_status_code: 301 paths: - /r1 diff --git a/tests/integration/testdata/sync/010-create-route-with-service-name-reference/kong.yaml b/tests/integration/testdata/sync/010-create-route-with-service-name-reference/kong.yaml index e80fcb693..70d332a32 100644 --- a/tests/integration/testdata/sync/010-create-route-with-service-name-reference/kong.yaml +++ b/tests/integration/testdata/sync/010-create-route-with-service-name-reference/kong.yaml @@ -9,7 +9,8 @@ services: read_timeout: 60000 retries: 5 routes: -- name: r1 +- id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + name: r1 https_redirect_status_code: 301 paths: - /r1 diff --git a/tests/integration/testdata/sync/xxx-plugins-on-entities/kong.yaml b/tests/integration/testdata/sync/xxx-plugins-on-entities/kong.yaml new file mode 100644 index 000000000..4f18b4eb2 --- /dev/null +++ b/tests/integration/testdata/sync/xxx-plugins-on-entities/kong.yaml @@ -0,0 +1,70 @@ +--- +_format_version: "1.1" +consumers: +- plugins: + - config: + day: null + fault_tolerant: true + header_name: null + hide_client_headers: false + hour: 10 + limit_by: consumer + minute: null + month: null + path: null + policy: cluster + redis_database: 0 + redis_host: null + redis_password: null + redis_port: 6379 + redis_server_name: null + redis_ssl: false + redis_ssl_verify: false + redis_timeout: 2000 + redis_username: null + second: null + year: null + enabled: true + name: rate-limiting + protocols: + - grpc + - grpcs + - http + - https + username: yolo + id: d2965b9b-0608-4458-a9f8-0b93d88d03b8 +services: +- id: 58076db2-28b6-423b-ba39-a797193017f7 + connect_timeout: 60000 + host: mockbin.org + name: svc1 + plugins: + - config: + per_consumer: false + enabled: true + name: prometheus + protocols: + - grpc + - grpcs + - http + - https + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + name: r1 + https_redirect_status_code: 301 + paths: + - /r1 + plugins: + - config: + per_consumer: false + enabled: true + name: prometheus + protocols: + - grpc + - grpcs + - http + - https \ No newline at end of file diff --git a/types/ca_cert.go b/types/ca_cert.go index cc9c9d155..995cba144 100644 --- a/types/ca_cert.go +++ b/types/ca_cert.go @@ -106,7 +106,7 @@ func (d *caCertificateDiffer) deleteCACertificate( } if err != nil { return nil, fmt.Errorf("looking up caCertificate %q: %w", - caCert.Identifier(), err) + caCert.FriendlyName(), err) } return nil, nil } @@ -148,7 +148,7 @@ func (d *caCertificateDiffer) createUpdateCACertificate( } if err != nil { return nil, fmt.Errorf("error looking up caCertificate %q: %w", - caCert.Identifier(), err) + caCert.FriendlyName(), err) } // found, check if update needed diff --git a/types/certificate.go b/types/certificate.go index 1a102a06b..ddbab616e 100644 --- a/types/certificate.go +++ b/types/certificate.go @@ -105,7 +105,7 @@ func (d *certificateDiffer) deleteCertificate( } if err != nil { return nil, fmt.Errorf("looking up certificate %q': %w", - certificate.Identifier(), err) + certificate.FriendlyName(), err) } return nil, nil } @@ -147,7 +147,7 @@ func (d *certificateDiffer) createUpdateCertificate( } if err != nil { return nil, fmt.Errorf("error looking up certificate %q: %w", - certificate.Identifier(), err) + certificate.FriendlyName(), err) } // found, check if update needed @@ -163,7 +163,7 @@ func (d *certificateDiffer) createUpdateCertificate( currentSNIs, err := d.currentState.SNIs.GetAllByCertID(*currentCertificate.ID) if err != nil { return nil, fmt.Errorf("error looking up current certificate SNIs %q: %w", - certificate.Identifier(), err) + certificate.FriendlyName(), err) } sniNames := make([]*string, 0) for _, s := range currentSNIs { diff --git a/types/consumer.go b/types/consumer.go index cb7b2c609..cf1c7406f 100644 --- a/types/consumer.go +++ b/types/consumer.go @@ -104,7 +104,7 @@ func (d *consumerDiffer) deleteConsumer(consumer *state.Consumer) (*crud.Event, } if err != nil { return nil, fmt.Errorf("looking up consumer %q: %w", - consumer.Identifier(), err) + consumer.FriendlyName(), err) } return nil, nil } @@ -144,7 +144,7 @@ func (d *consumerDiffer) createUpdateConsumer(consumer *state.Consumer) (*crud.E } if err != nil { return nil, fmt.Errorf("error looking up consumer %q: %w", - consumer.Identifier(), err) + consumer.FriendlyName(), err) } // found, check if update needed diff --git a/types/postProcess.go b/types/postProcess.go index 6195cded4..ab079cad5 100644 --- a/types/postProcess.go +++ b/types/postProcess.go @@ -290,7 +290,7 @@ func (crud *rbacEndpointPermissionPostAction) Create(ctx context.Context, args . } func (crud *rbacEndpointPermissionPostAction) Delete(ctx context.Context, args ...crud.Arg) (crud.Arg, error) { - return nil, crud.currentState.RBACEndpointPermissions.Delete(args[0].(*state.RBACEndpointPermission).Identifier()) + return nil, crud.currentState.RBACEndpointPermissions.Delete(args[0].(*state.RBACEndpointPermission).FriendlyName()) } func (crud *rbacEndpointPermissionPostAction) Update(ctx context.Context, args ...crud.Arg) (crud.Arg, error) { diff --git a/types/rbac_endpoint_permission.go b/types/rbac_endpoint_permission.go index 7cbbbc3e2..20f594b0a 100644 --- a/types/rbac_endpoint_permission.go +++ b/types/rbac_endpoint_permission.go @@ -106,7 +106,7 @@ type rbacEndpointPermissionDiffer struct { func (d *rbacEndpointPermissionDiffer) deleteRBACEndpointPermission(ep *state.RBACEndpointPermission) ( *crud.Event, error, ) { - _, err := d.targetState.RBACEndpointPermissions.Get(ep.Identifier()) + _, err := d.targetState.RBACEndpointPermissions.Get(ep.FriendlyName()) if err == state.ErrNotFound { return &crud.Event{ Op: crud.Delete, @@ -146,7 +146,7 @@ func (d *rbacEndpointPermissionDiffer) createUpdateRBACEndpointPermission(ep *st *crud.Event, error, ) { epCopy := &state.RBACEndpointPermission{RBACEndpointPermission: *ep.DeepCopy()} - currentEp, err := d.currentState.RBACEndpointPermissions.Get(ep.Identifier()) + currentEp, err := d.currentState.RBACEndpointPermissions.Get(ep.FriendlyName()) if err == state.ErrNotFound { return &crud.Event{ @@ -157,7 +157,7 @@ func (d *rbacEndpointPermissionDiffer) createUpdateRBACEndpointPermission(ep *st } if err != nil { return nil, fmt.Errorf("error looking up rbac endpoint permission %q: %w", - ep.Identifier(), err) + ep.FriendlyName(), err) } // found, check if update needed diff --git a/types/rbac_role.go b/types/rbac_role.go index add43b015..c89ed76ac 100644 --- a/types/rbac_role.go +++ b/types/rbac_role.go @@ -105,7 +105,7 @@ func (d *rbacRoleDiffer) deleteRBACRole(role *state.RBACRole) (*crud.Event, erro } if err != nil { return nil, fmt.Errorf("looking up rbac role %q: %w", - role.Identifier(), err) + role.FriendlyName(), err) } return nil, nil } @@ -144,7 +144,7 @@ func (d *rbacRoleDiffer) createUpdateRBACRole(role *state.RBACRole) (*crud.Event } if err != nil { return nil, fmt.Errorf("error looking up rbac role %q: %w", - role.Identifier(), err) + role.FriendlyName(), err) } // found, check if update needed diff --git a/types/route.go b/types/route.go index a7d3edf1f..15a082c97 100644 --- a/types/route.go +++ b/types/route.go @@ -104,7 +104,7 @@ func (d *routeDiffer) deleteRoute(route *state.Route) (*crud.Event, error) { } if err != nil { return nil, fmt.Errorf("looking up route %q: %w", - route.Identifier(), err) + route.FriendlyName(), err) } return nil, nil } @@ -144,7 +144,7 @@ func (d *routeDiffer) createUpdateRoute(route *state.Route) (*crud.Event, error) } if err != nil { return nil, fmt.Errorf("error looking up route %q: %w", - route.Identifier(), err) + route.FriendlyName(), err) } // found, check if update needed diff --git a/types/service.go b/types/service.go index 75adc3651..3bfee19f3 100644 --- a/types/service.go +++ b/types/service.go @@ -104,7 +104,7 @@ func (d *serviceDiffer) deleteService(service *state.Service) (*crud.Event, erro } if err != nil { return nil, fmt.Errorf("looking up service %q: %w", - service.Identifier(), err) + service.FriendlyName(), err) } return nil, nil } diff --git a/utils/utils.go b/utils/utils.go index d7781e799..8f35a0c26 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -101,3 +101,41 @@ func WorkspaceExists(ctx context.Context, client *kong.Client) (bool, error) { } return client.Workspaces.Exists(ctx, &workspace) } + +// These GetFooReference functions return stripped copies (ID and Name only) of Kong resource +// structs. We use these within KongRawState structs to indicate entity relationships. +// While state files indicate relationships by nesting (A collection of services is +// [{name: "foo", id: "1234", connect_timeout: 600000, routes: [{name: "fooRoute"}]}]), +// KongRawState is flattened, with all entities listed independently at the top level. +// To preserve the relationships, these flattened entities include references (the route from +// earlier becomes {name: "fooRoute", service: {name: "foo", id: "1234"}}). + +// GetConsumerReference returns a username+ID only copy of the input consumer, +// for use in references from other objects +func GetConsumerReference(c kong.Consumer) *kong.Consumer { + consumer := &kong.Consumer{ID: kong.String(*c.ID)} + if c.Username != nil { + consumer.Username = kong.String(*c.Username) + } + return consumer +} + +// GetServiceReference returns a name+ID only copy of the input service, +// for use in references from other objects +func GetServiceReference(s kong.Service) *kong.Service { + service := &kong.Service{ID: kong.String(*s.ID)} + if s.Name != nil { + service.Name = kong.String(*s.Name) + } + return service +} + +// GetRouteReference returns a name+ID only copy of the input route, +// for use in references from other objects +func GetRouteReference(r kong.Route) *kong.Route { + route := &kong.Route{ID: kong.String(*r.ID)} + if r.Name != nil { + route.Name = kong.String(*r.Name) + } + return route +}