Skip to content

Commit

Permalink
feat: FilterChain entity
Browse files Browse the repository at this point in the history
  • Loading branch information
hishamhm committed Jul 28, 2023
1 parent da09634 commit ba69f3f
Show file tree
Hide file tree
Showing 5 changed files with 980 additions and 0 deletions.
2 changes: 2 additions & 0 deletions kong/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ type Client struct {
Keys AbstractKeyService
KeySets AbstractKeySetService
Licenses AbstractLicenseService
FilterChains AbstractFilterChainService

credentials abstractCredentialService
KeyAuths AbstractKeyAuthService
Expand Down Expand Up @@ -160,6 +161,7 @@ func NewClient(baseURL *string, client *http.Client) (*Client, error) {
kong.Keys = (*KeyService)(&kong.common)
kong.KeySets = (*KeySetService)(&kong.common)
kong.Licenses = (*LicenseService)(&kong.common)
kong.FilterChains = (*FilterChainService)(&kong.common)

kong.credentials = (*credentialService)(&kong.common)
kong.KeyAuths = (*KeyAuthService)(&kong.common)
Expand Down
35 changes: 35 additions & 0 deletions kong/filter_chain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package kong

// FilterChain represents a FilterChain in Kong.
// Read https://docs.konghq.com/gateway/latest/admin-api/#filter-chain-object
// +k8s:deepcopy-gen=true
type FilterChain struct {
ID *string `json:"id,omitempty" yaml:"id,omitempty"`
Name *string `json:"name,omitempty" yaml:"name,omitempty"`
Enabled *bool `json:"enabled,omitempty" yaml:"enabled,omitempty"`
Route *Route `json:"route,omitempty" yaml:"route,omitempty"`
Service *Service `json:"service,omitempty" yaml:"service,omitempty"`
Filters []*Filter `json:"filters,omitempty" yaml:"filters,omitempty"`
CreatedAt *int `json:"created_at,omitempty" yaml:"created_at,omitempty"`
UpdatedAt *int `json:"updated_at,omitempty" yaml:"updated_at,omitempty"`
Tags []*string `json:"tags,omitempty" yaml:"tags,omitempty"`
}

// Filter contains information about each filter in the chain
// +k8s:deepcopy-gen=true
type Filter struct {
Name *string `json:"name,omitempty" yaml:"name,omitempty"`
Config *string `json:"config,omitempty" yaml:"config,omitempty"`
Enabled *bool `json:"enabled,omitempty" yaml:"enabled,omitempty"`
}

// FriendlyName returns the endpoint key name or ID.
func (f *FilterChain) FriendlyName() string {
if f.Name != nil {
return *f.Name
}
if f.ID != nil {
return *f.ID
}
return ""
}
333 changes: 333 additions & 0 deletions kong/filter_chain_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
package kong

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

// AbstractFilterChainService handles FilterChains in Kong.
type AbstractFilterChainService interface {
// Create creates a FilterChain in Kong.
Create(ctx context.Context, filterChain *FilterChain) (*FilterChain, error)
// CreateForService creates a FilterChain in Kong.
CreateForService(ctx context.Context, serviceIDorName *string, filterChain *FilterChain) (*FilterChain, error)
// CreateForRoute creates a FilterChain in Kong.
CreateForRoute(ctx context.Context, routeIDorName *string, filterChain *FilterChain) (*FilterChain, error)
// Get fetches a FilterChain in Kong.
Get(ctx context.Context, nameOrID *string) (*FilterChain, error)
// Update updates a FilterChain in Kong
Update(ctx context.Context, filterChain *FilterChain) (*FilterChain, error)
// UpdateForService updates a FilterChain in Kong for a service
UpdateForService(ctx context.Context, serviceIDorName *string, filterChain *FilterChain) (*FilterChain, error)
// UpdateForRoute updates a FilterChain in Kong for a service
UpdateForRoute(ctx context.Context, routeIDorName *string, filterChain *FilterChain) (*FilterChain, error)
// Delete deletes a FilterChain in Kong
Delete(ctx context.Context, nameOrID *string) error
// DeleteForService deletes a FilterChain in Kong
DeleteForService(ctx context.Context, serviceIDorName *string, filterChainID *string) error
// DeleteForRoute deletes a FilterChain in Kong
DeleteForRoute(ctx context.Context, routeIDorName *string, filterChainID *string) error
// List fetches a list of FilterChains in Kong.
List(ctx context.Context, opt *ListOpt) ([]*FilterChain, *ListOpt, error)
// ListAll fetches all FilterChains in Kong.
ListAll(ctx context.Context) ([]*FilterChain, error)
// ListAllForService fetches all FilterChains in Kong enabled for a service.
ListAllForService(ctx context.Context, serviceIDorName *string) ([]*FilterChain, error)
// ListAllForRoute fetches all FilterChains in Kong enabled for a service.
ListAllForRoute(ctx context.Context, routeID *string) ([]*FilterChain, error)
}

// FilterChainService handles FilterChains in Kong.
type FilterChainService service

// Create creates a FilterChain in Kong.
// If an ID is specified, it will be used to
// create a filter chain in Kong, otherwise an ID
// is auto-generated.
func (s *FilterChainService) Create(ctx context.Context,
filterChain *FilterChain,
) (*FilterChain, error) {
queryPath := "/filter-chains"
method := "POST"
if filterChain.ID != nil {
queryPath = queryPath + "/" + *filterChain.ID
method = "PUT"
}
return s.sendRequest(ctx, filterChain, queryPath, method)
}

// CreateForService creates a FilterChain in Kong at Service level.
// If an ID is specified, it will be used to
// create a filter chain in Kong, otherwise an ID
// is auto-generated.
func (s *FilterChainService) CreateForService(ctx context.Context,
serviceIDorName *string, filterChain *FilterChain,
) (*FilterChain, error) {
queryPath := "/filter-chains"
method := "POST"
if filterChain.ID != nil {
queryPath = queryPath + "/" + *filterChain.ID
method = "PUT"
}
if isEmptyString(serviceIDorName) {
return nil, fmt.Errorf("serviceIDorName cannot be nil")
}

return s.sendRequest(ctx, filterChain, fmt.Sprintf("/services/%v"+queryPath, *serviceIDorName), method)
}

// CreateForRoute creates a FilterChain in Kong at Route level.
// If an ID is specified, it will be used to
// create a filter chain in Kong, otherwise an ID
// is auto-generated.
func (s *FilterChainService) CreateForRoute(ctx context.Context,
routeIDorName *string, filterChain *FilterChain,
) (*FilterChain, error) {
queryPath := "/filter-chains"
method := "POST"

if filterChain.ID != nil {
queryPath = queryPath + "/" + *filterChain.ID
method = "PUT"
}
if isEmptyString(routeIDorName) {
return nil, fmt.Errorf("routeIDorName cannot be nil")
}

return s.sendRequest(ctx, filterChain, fmt.Sprintf("/routes/%v"+queryPath, *routeIDorName), method)
}

// Get fetches a FilterChain in Kong.
func (s *FilterChainService) Get(ctx context.Context,
nameOrID *string,
) (*FilterChain, error) {
if isEmptyString(nameOrID) {
return nil, fmt.Errorf("nameOrID cannot be nil for Get operation")
}

endpoint := fmt.Sprintf("/filter-chains/%v", *nameOrID)
req, err := s.client.NewRequest("GET", endpoint, nil, nil)
if err != nil {
return nil, err
}

var filterChain FilterChain
_, err = s.client.Do(ctx, req, &filterChain)
if err != nil {
return nil, err
}
return &filterChain, nil
}

// Update updates a FilterChain in Kong
func (s *FilterChainService) Update(ctx context.Context,
filterChain *FilterChain,
) (*FilterChain, error) {
if isEmptyString(filterChain.ID) {
return nil, fmt.Errorf("ID cannot be nil for Update operation")
}

endpoint := fmt.Sprintf("/filter-chains/%v", *filterChain.ID)
return s.sendRequest(ctx, filterChain, endpoint, "PATCH")
}

// UpdateForService updates a FilterChain in Kong at Service level.
func (s *FilterChainService) UpdateForService(ctx context.Context,
serviceIDorName *string, filterChain *FilterChain,
) (*FilterChain, error) {
if isEmptyString(filterChain.ID) {
return nil, fmt.Errorf("ID cannot be nil for Update operation")
}
if isEmptyString(serviceIDorName) {
return nil, fmt.Errorf("serviceIDorName cannot be nil")
}

endpoint := fmt.Sprintf("/services/%v/filter-chains/%v", *serviceIDorName, *filterChain.ID)
return s.sendRequest(ctx, filterChain, endpoint, "PATCH")
}

// UpdateForRoute updates a FilterChain in Kong at Route level.
func (s *FilterChainService) UpdateForRoute(ctx context.Context,
routeIDorName *string, filterChain *FilterChain,
) (*FilterChain, error) {
if isEmptyString(filterChain.ID) {
return nil, fmt.Errorf("ID cannot be nil for Update operation")
}
if isEmptyString(routeIDorName) {
return nil, fmt.Errorf("routeIDorName cannot be nil")
}

endpoint := fmt.Sprintf("/routes/%v/filter-chains/%v", *routeIDorName, *filterChain.ID)
return s.sendRequest(ctx, filterChain, endpoint, "PATCH")
}

// Delete deletes a FilterChain in Kong
func (s *FilterChainService) Delete(ctx context.Context,
filterChainID *string,
) error {
if isEmptyString(filterChainID) {
return fmt.Errorf("filterChainID cannot be nil for Delete operation")
}

endpoint := fmt.Sprintf("/filter-chains/%v", *filterChainID)
_, err := s.sendRequest(ctx, nil, endpoint, "DELETE")
if err != nil {
return err
}
return err
}

// DeleteForService deletes a FilterChain in Kong at Service level.
func (s *FilterChainService) DeleteForService(ctx context.Context,
serviceIDorName *string, filterChainID *string,
) error {
if isEmptyString(filterChainID) {
return fmt.Errorf("filterChain ID cannot be nil for Delete operation")
}
if isEmptyString(serviceIDorName) {
return fmt.Errorf("serviceIDorName cannot be nil")
}

endpoint := fmt.Sprintf("/services/%v/filter-chains/%v", *serviceIDorName, *filterChainID)
_, err := s.sendRequest(ctx, nil, endpoint, "DELETE")
if err != nil {
return err
}
return err
}

// DeleteForRoute deletes a FilterChain in Kong at Route level.
func (s *FilterChainService) DeleteForRoute(ctx context.Context,
routeIDorName *string, filterChainID *string,
) error {
if isEmptyString(filterChainID) {
return fmt.Errorf("filterChain ID cannot be nil for Delete operation")
}
if isEmptyString(routeIDorName) {
return fmt.Errorf("routeIDorName cannot be nil")
}

endpoint := fmt.Sprintf("/routes/%v/filter-chains/%v", *routeIDorName, *filterChainID)
_, err := s.sendRequest(ctx, nil, endpoint, "DELETE")
if err != nil {
return err
}
return nil
}

// listByPath fetches a list of FilterChains in Kong
// on a specific path.
// This is a helper method for listing all filter chains
// or filter chains for specific entities.
func (s *FilterChainService) listByPath(ctx context.Context,
path string, opt *ListOpt,
) ([]*FilterChain, *ListOpt, error) {
data, next, err := s.client.list(ctx, path, opt)
if err != nil {
return nil, nil, err
}
var filterChains []*FilterChain

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

return filterChains, next, nil
}

// ListAll fetches all FilterChains in Kong.
// This method can take a while if there
// a lot of FilterChains present.
func (s *FilterChainService) listAllByPath(ctx context.Context,
path string,
) ([]*FilterChain, error) {
var filterChains, data []*FilterChain
var err error
opt := &ListOpt{Size: pageSize}

for opt != nil {
data, opt, err = s.listByPath(ctx, path, opt)
if err != nil {
return nil, err
}
filterChains = append(filterChains, data...)
}
return filterChains, nil
}

// List fetches a list of FilterChains in Kong.
// opt can be used to control pagination.
func (s *FilterChainService) List(ctx context.Context,
opt *ListOpt,
) ([]*FilterChain, *ListOpt, error) {
return s.listByPath(ctx, "/filter-chains", opt)
}

// ListAll fetches all FilterChains in Kong.
// This method can take a while if there
// a lot of FilterChains present.
func (s *FilterChainService) ListAll(ctx context.Context) ([]*FilterChain, error) {
return s.listAllByPath(ctx, "/filter-chains")
}

// ListAllForService fetches all FilterChains in Kong enabled for a service.
func (s *FilterChainService) ListAllForService(ctx context.Context,
serviceIDorName *string,
) ([]*FilterChain, error) {
if isEmptyString(serviceIDorName) {
return nil, fmt.Errorf("serviceIDorName cannot be nil")
}
return s.listAllByPath(ctx, "/services/"+*serviceIDorName+"/filter-chains")
}

// ListAllForRoute fetches all FilterChains in Kong enabled for a service.
func (s *FilterChainService) ListAllForRoute(ctx context.Context,
routeID *string,
) ([]*FilterChain, error) {
if isEmptyString(routeID) {
return nil, fmt.Errorf("routeID cannot be nil")
}
return s.listAllByPath(ctx, "/routes/"+*routeID+"/filter-chains")
}

func (s *FilterChainService) sendRequest(ctx context.Context,
filterChain *FilterChain, endpoint, method string,
) (*FilterChain, error) {
var req *http.Request
var err error
if method == "DELETE" {
req, err = s.client.NewRequest(method, endpoint, nil, nil)
if err != nil {
return nil, err
}
} else {
req, err = s.client.NewRequest(method, endpoint, nil, filterChain)
if err != nil {
return nil, err
}
}
var createdFilterChain FilterChain
if method == "DELETE" {
_, err = s.client.Do(ctx, req, nil)
if err != nil {
return nil, err
}
} else {
_, err = s.client.Do(ctx, req, &createdFilterChain)
if err != nil {
return nil, err
}
}
return &createdFilterChain, nil
}
Loading

0 comments on commit ba69f3f

Please sign in to comment.