Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: client apis to interact with the konnect applications #490

Merged
merged 16 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@
- [0.2.0](#020)
- [0.1.0](#010)

## [v0.62.0]

> Release date: 2024/12/11

- Added Client APIs (Create, List, ListALL, Delete) to interact
with the Konnect Application Auth resources.
[#490](https://github.com/Kong/go-kong/pull/490)

## [v0.61.0]

> Release date: 2024/12/06
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/samber/lo v1.47.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc=
github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down
2 changes: 2 additions & 0 deletions kong/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type Client struct {
Vaults AbstractVaultService
Keys AbstractKeyService
KeySets AbstractKeySetService
KonnectApplication AbstractKonnectApplicationService
Licenses AbstractLicenseService
FilterChains AbstractFilterChainService

Expand Down Expand Up @@ -165,6 +166,7 @@ func NewClient(baseURL *string, client *http.Client) (*Client, error) {
kong.Vaults = (*VaultService)(&kong.common)
kong.Keys = (*KeyService)(&kong.common)
kong.KeySets = (*KeySetService)(&kong.common)
kong.KonnectApplication = (*KonnectApplicationService)(&kong.common)
kong.Licenses = (*LicenseService)(&kong.common)
kong.FilterChains = (*FilterChainService)(&kong.common)

Expand Down
27 changes: 27 additions & 0 deletions kong/konnect_application.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package kong

// KonnectApplication represents Konnect-Application-Auth
// in Kong.
// Read https://docs.konghq.com/konnect/dev-portal/applications/application-overview/
// +k8s:deepcopy-gen=true
type KonnectApplication struct {
ID *string `json:"id"`
CreatedAt int64 `json:"created_at"`
ClientID string `json:"client_id"`
ConsumerGroups []string `json:"consumer_groups"`
Scopes []string `json:"scopes"`
AuthStrategyID *string `json:"auth_strategy_id"`
ApplicationContext *ApplicationContext `json:"application_context"`
ExhaustedScopes []string `json:"exhausted_scopes"`
Tags *[]string `json:"tags"`
}

// ApplicationContext represents the application context inside the
// Konnenct-Application-Auth.
// +k8s:deepcopy-gen=true
type ApplicationContext struct {
PortalID *string `json:"portal_id"`
ApplicationID *string `json:"application_id"`
DeveloperID *string `json:"developer_id"`
OrganizationID *string `json:"organization_id"`
}
105 changes: 105 additions & 0 deletions kong/konnect_application_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package kong

import (
"context"
"encoding/json"
"fmt"
"net/http"
)

var _ AbstractKonnectApplicationService = &KonnectApplicationService{}

// AbstractKonnectApplicationService handles Konnect applications in Kong.
type AbstractKonnectApplicationService interface {
// Create creates a Konnect Application in Kong.
Create(ctx context.Context, key *KonnectApplication) (*KonnectApplication, error)
// List fetches list of Konnect Applications in Kong.
List(ctx context.Context, opt *ListOpt) ([]*KonnectApplication, *ListOpt, error)
// ListAll fetches all Konnect Applications in Kong.
ListAll(ctx context.Context) ([]*KonnectApplication, error)
// Delete deletes a Konnect Application in Kong by ID.
Delete(ctx context.Context, ID *string) error
}

type KonnectApplicationService service

// Create creates a Konnect Application in Kong.
func (k *KonnectApplicationService) Create(ctx context.Context, key *KonnectApplication) (*KonnectApplication, error) {
queryPath := "/konnect_applications"
method := "POST"
if key.ID != nil {
queryPath = queryPath + "/" + *key.ID
method = "PUT"
}
req, err := k.client.NewRequest(method, queryPath, nil, key)
if err != nil {
return nil, err
}

var createdKey KonnectApplication
_, err = k.client.Do(ctx, req, &createdKey)
if err != nil {
return nil, err
}
return &createdKey, nil
}

// List fetches list of Konnect Applications in Kong.
func (k *KonnectApplicationService) List(ctx context.Context, opt *ListOpt) ([]*KonnectApplication, *ListOpt, error) {
data, next, err := k.client.list(ctx, "/konnect_applications", opt)
if err != nil {
return nil, nil, err
}
var kaas []*KonnectApplication

for _, object := range data {
b, err := object.MarshalJSON()
if err != nil {
return nil, nil, err
}
var kaa KonnectApplication
err = json.Unmarshal(b, &kaa)
if err != nil {
return nil, nil, err
}
kaas = append(kaas, &kaa)
}

return kaas, next, nil
}

// ListAll fetches all Konnect Applications in Kong.
func (k *KonnectApplicationService) ListAll(ctx context.Context) ([]*KonnectApplication, error) {
var kaa, data []*KonnectApplication
var err error
opt := &ListOpt{Size: pageSize}

for opt != nil {
data, opt, err = k.List(ctx, opt)
if err != nil {
return nil, err
}
kaa = append(kaa, data...)
}
return kaa, nil
}

// Delete deletes a Konnect Application in Kong by ID.
func (k *KonnectApplicationService) Delete(ctx context.Context, ID *string) error {
if isEmptyString(ID) {
return fmt.Errorf("ID cannot be nil for Delete operation")
}

req, err := k.client.NewRequest("DELETE", fmt.Sprintf("/konnect_applications/%s", *ID), nil, nil)
if err != nil {
return err
}

resp, err := k.client.Do(ctx, req, nil)
if resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("failed to delete Konnect Application: %s: "+
"expected status %v, but received %v", *ID, http.StatusNoContent, resp.Status)
}

return err
}
203 changes: 203 additions & 0 deletions kong/konnect_application_service_test.go
pmalek marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
package kong

import (
"context"
"testing"
"time"

"github.com/google/uuid"
"github.com/samber/lo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestKonnectApplicationService_Create(T *testing.T) {
RunWhenDBMode(T, "postgres")
RunWhenEnterprise(T, ">=3.6.0", RequiredFeatures{})

assert := assert.New(T)
require := require.New(T)

client, err := NewTestClient(nil, nil)
require.NoError(err)
require.NotNil(client)

var (
clientID = uuid.NewString()
consumerGroup = []string{uuid.NewString()}
scopes = []string{"/auth"}
authStrategyID = uuid.NewString()
exhaustedScopes = []string{"/eauth"}
orgID = uuid.NewString()
developerID = uuid.NewString()
createdAt = time.Now().Unix()
)

kaa := &KonnectApplication{
ID: &clientID,
ClientID: clientID,
ConsumerGroups: consumerGroup,
Scopes: scopes,
AuthStrategyID: &authStrategyID,
ExhaustedScopes: exhaustedScopes,
ApplicationContext: &ApplicationContext{
OrganizationID: &orgID,
DeveloperID: &developerID,
},
CreatedAt: createdAt,
}
createResponse, err := client.KonnectApplication.Create(defaultCtx, kaa)
require.NoError(err)
require.NotNil(createResponse)

T.Cleanup(func() {
assert.NoError(client.KonnectApplication.Delete(context.Background(), createResponse.ID))
})

require.Equal(createResponse.ClientID, clientID)
require.Equal(createResponse.CreatedAt, createdAt)
require.Equal(createResponse.ConsumerGroups, consumerGroup)
require.Equal(createResponse.Scopes, scopes)
require.Equal(createResponse.ExhaustedScopes, exhaustedScopes)
}

func TestKonnectApplicationService_ListAll(T *testing.T) {
RunWhenDBMode(T, "postgres")
RunWhenEnterprise(T, ">=3.6.0", RequiredFeatures{})

assert := assert.New(T)
require := require.New(T)

client, err := NewTestClient(nil, nil)
require.NoError(err)
require.NotNil(client)

var (
expectedKonnectApplications = 10
consumerGroup = []string{uuid.NewString()}
scopes = []string{"/auth"}
authStrategyID = uuid.NewString()
exhaustedScopes = []string{"/eauth"}
orgID = uuid.NewString()
developerID = uuid.NewString()
createdAt = time.Now().Unix()
)

kaa := &KonnectApplication{
ConsumerGroups: consumerGroup,
Scopes: scopes,
AuthStrategyID: &authStrategyID,
ExhaustedScopes: exhaustedScopes,
ApplicationContext: &ApplicationContext{
OrganizationID: &orgID,
DeveloperID: &developerID,
},
CreatedAt: createdAt,
}

for i := 0; i < expectedKonnectApplications; i++ {
clientID := uuid.NewString()
kaa.ID = &clientID
kaa.ClientID = clientID
createResponse, err := client.KonnectApplication.Create(defaultCtx, kaa)
require.NoError(err)
require.NotNil(createResponse)
reversearrow marked this conversation as resolved.
Show resolved Hide resolved

T.Cleanup(func() {
assert.NoError(client.KonnectApplication.Delete(context.Background(), createResponse.ID))
})
}

listKonnectApplicationResponse, err := client.KonnectApplication.ListAll(defaultCtx)
require.NoError(err)
require.Len(listKonnectApplicationResponse, expectedKonnectApplications)
}

func TestKonnectApplicationService_List(T *testing.T) {
RunWhenDBMode(T, "postgres")
RunWhenEnterprise(T, ">=3.6.0", RequiredFeatures{})

assert := assert.New(T)
require := require.New(T)

client, err := NewTestClient(nil, nil)
require.NoError(err)
require.NotNil(client)

var (
expectedKonnectApplications = 10
consumerGroup = []string{uuid.NewString()}
scopes = []string{"/auth"}
authStrategyID = uuid.NewString()
exhaustedScopes = []string{"/eauth"}
orgID = uuid.NewString()
developerID = uuid.NewString()
createdAt = time.Now().Unix()
tagA = "list1"
tagB = "list2"
)

kaa := &KonnectApplication{
ConsumerGroups: consumerGroup,
Scopes: scopes,
AuthStrategyID: &authStrategyID,
ExhaustedScopes: exhaustedScopes,
ApplicationContext: &ApplicationContext{
OrganizationID: &orgID,
DeveloperID: &developerID,
},
CreatedAt: createdAt,
}

for i := 0; i < expectedKonnectApplications/2; i++ {
clientID := uuid.NewString()
kaa.ID = &clientID
kaa.ClientID = clientID
kaa.Tags = lo.ToPtr([]string{tagA})
createResponse, err := client.KonnectApplication.Create(defaultCtx, kaa)
require.NoError(err)
require.NotNil(createResponse)

T.Cleanup(func() {
assert.NoError(client.KonnectApplication.Delete(context.Background(), createResponse.ID))
})
}

for i := 0; i < expectedKonnectApplications/2; i++ {
clientID := uuid.NewString()
kaa.ID = &clientID
kaa.ClientID = clientID
kaa.Tags = lo.ToPtr([]string{tagB})
createResponse, err := client.KonnectApplication.Create(defaultCtx, kaa)
require.NoError(err)
require.NotNil(createResponse)

T.Cleanup(func() {
assert.NoError(client.KonnectApplication.Delete(context.Background(), createResponse.ID))
})
}

// Filter by tag listA
listKonnectApplicationResponseByTagA, _, err := client.KonnectApplication.List(defaultCtx, &ListOpt{
Size: 10,
Tags: []*string{lo.ToPtr(tagA)},
})
require.NoError(err)
require.Len(listKonnectApplicationResponseByTagA, 5)

// Filter by tag listB
listKonnectApplicationResponseByTagB, _, err := client.KonnectApplication.List(defaultCtx, &ListOpt{
Size: 10,
Tags: []*string{lo.ToPtr(tagB)},
})
require.NoError(err)
require.Len(listKonnectApplicationResponseByTagB, 5)

size := 2
// Filter by size
listKonnectApplicationResponseBySize, _, err := client.KonnectApplication.List(defaultCtx, &ListOpt{
Size: size,
})
require.NoError(err)
require.Len(listKonnectApplicationResponseBySize, size)
}
Loading
Loading