Skip to content

Commit

Permalink
APIGOV-26621 get spec from dev portal
Browse files Browse the repository at this point in the history
  • Loading branch information
alrosca committed Nov 17, 2023
1 parent b7934b6 commit 15ffe60
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 15 deletions.
23 changes: 13 additions & 10 deletions pkg/cmd/discovery/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ var DiscoveryCmd corecmd.AgentRootCmd
var agentConfig config.AgentConfig

const (
cfgKongAdminURL = "kong.admin.url"
cfgKongAdminAPIKey = "kong.admin.auth.apikey.value"
cfgKongAdminAPIKeyHeader = "kong.admin.auth.apikey.header"
cfgKongProxyHost = "kong.proxy.host"
cfgKongProxyPortHttp = "kong.proxy.port.http"
cfgKongProxyPortHttps = "kong.proxy.port.https"
cfgKongSpecURLPaths = "kong.spec.urlPaths"
cfgKongSpecLocalPath = "kong.spec.localPath"
cfgKongAdminURL = "kong.admin.url"
cfgKongAdminAPIKey = "kong.admin.auth.apikey.value"
cfgKongAdminAPIKeyHeader = "kong.admin.auth.apikey.header"
cfgKongProxyHost = "kong.proxy.host"
cfgKongProxyPortHttp = "kong.proxy.port.http"
cfgKongProxyPortHttps = "kong.proxy.port.https"
cfgKongSpecURLPaths = "kong.spec.urlPaths"
cfgKongSpecLocalPath = "kong.spec.localPath"
cfgKongSpecDevPortalEnabled = "kong.spec.devPortalEnabled"
)

func init() {
Expand All @@ -45,6 +46,7 @@ func init() {
rootProps.AddIntProperty(cfgKongProxyPortHttps, 443, "The Kong proxy https port")
rootProps.AddStringSliceProperty(cfgKongSpecURLPaths, []string{}, "URL paths that the agent will look in for spec files")
rootProps.AddStringProperty(cfgKongSpecLocalPath, "", "Local paths where the agent will look for spec files")
rootProps.AddBoolProperty(cfgKongSpecDevPortalEnabled, false, "Dev Portal is used to download spec files")
}

// Callback that agent will call to process the execution
Expand Down Expand Up @@ -99,8 +101,9 @@ func initConfig(centralConfig corecfg.CentralConfig) (interface{}, error) {
},
},
Spec: config.KongSpecConfig{
URLPaths: rootProps.StringSlicePropertyValue(cfgKongSpecURLPaths),
LocalPath: rootProps.StringPropertyValue(cfgKongSpecLocalPath),
URLPaths: rootProps.StringSlicePropertyValue(cfgKongSpecURLPaths),
LocalPath: rootProps.StringPropertyValue(cfgKongSpecLocalPath),
DevPortalEnabled: rootProps.BoolPropertyValue(cfgKongSpecDevPortalEnabled),
},
}

Expand Down
5 changes: 3 additions & 2 deletions pkg/config/discovery/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ type KongProxyPortConfig struct {
}

type KongSpecConfig struct {
URLPaths []string `config:"urlPaths"`
LocalPath string `config:"localPaths"`
URLPaths []string `config:"urlPaths"`
LocalPath string `config:"localPath"`
DevPortalEnabled bool `config:"devPortalEnabled"`
}

// KongGatewayConfig - represents the config for gateway
Expand Down
72 changes: 69 additions & 3 deletions pkg/kong/kongclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package kong
import (
"context"
"crypto/tls"
"encoding/json"
"fmt"
"io"
"net/http"
Expand Down Expand Up @@ -44,13 +45,22 @@ type KongAPIClient interface {
GetKongPlugins() *Plugins
}

type KongServiceSpec struct {
Contents string `json:"contents"`
CreatedAt int `json:"created_at"`
ID string `json:"id"`
Path string `json:"path"`
Checksum string `json:"checksum"`
}

type KongClient struct {
*klib.Client
logger log.FieldLogger
baseClient DoRequest
kongAdminEndpoint string
specURLPaths []string
specLocalPath string
devPortalEnabled bool
clientTimeout time.Duration
}

Expand Down Expand Up @@ -80,6 +90,7 @@ func NewKongClient(baseClient *http.Client, kongConfig *config.KongGatewayConfig
kongAdminEndpoint: kongConfig.Admin.URL,
specURLPaths: kongConfig.Spec.URLPaths,
specLocalPath: kongConfig.Spec.LocalPath,
devPortalEnabled: kongConfig.Spec.DevPortalEnabled,
clientTimeout: 60 * time.Second,
}, nil
}
Expand All @@ -100,6 +111,10 @@ func (k KongClient) GetSpecForService(ctx context.Context, service *klib.Service
return k.getSpecFromLocal(ctx, service)
}

if k.devPortalEnabled {
return k.getSpecFromDevPortal(ctx, *service.ID)
}

// all three fields are needed to form the backend URL used in discovery process
if service.Protocol == nil && service.Host == nil {
err := fmt.Errorf("fields for backend URL are not set")
Expand All @@ -116,6 +131,7 @@ func (k KongClient) GetSpecForService(ctx context.Context, service *klib.Service

func (k KongClient) getSpecFromLocal(ctx context.Context, service *klib.Service) ([]byte, error) {
log := k.logger.WithField("serviceID", service.ID).WithField("serviceName", service.Name)
log.Info("getting spec from local storage")

specTag := ""
for _, tag := range service.Tags {
Expand Down Expand Up @@ -157,7 +173,44 @@ func (k KongClient) loadSpecFile(specFilePath string) ([]byte, error) {
return data, nil
}

func (k KongClient) getSpecFromDevPortal(ctx context.Context, serviceID string) ([]byte, error) {
log := k.logger.WithField("serviceID", serviceID)
log.Info("getting spec file from dev portal")

endpoint := fmt.Sprintf("%s/services/%s/document_objects", k.kongAdminEndpoint, serviceID)
req, err := http.NewRequestWithContext(ctx, "GET", endpoint, nil)
if err != nil {
log.WithError(err).Error("failed to create request")
return nil, err
}
res, err := k.baseClient.Do(req)
if err != nil {
log.WithError(err).Error("failed to execute request")
return nil, err
}
data, err := io.ReadAll(res.Body)
if err != nil {
log.WithError(err).Error("failed to read body")
return nil, err
}
documents := &DocumentObjects{}
err = json.Unmarshal(data, documents)
if err != nil {
log.WithError(err).Error("failed to unmarshal")
return nil, err
}
if len(documents.Data) < 1 {
log.Debug("no documents found")
return nil, nil
}

endpoint = fmt.Sprintf("%s/default/files/%s", k.kongAdminEndpoint, documents.Data[0].Path)
return k.getSpec(ctx, endpoint, true)
}

func (k KongClient) getSpecFromBackend(ctx context.Context, backendURL string) ([]byte, error) {
k.logger.Info("trying to get spec file from service backend")

if len(k.specURLPaths) == 0 {
k.logger.Info("no spec paths configured")
return nil, nil
Expand All @@ -166,7 +219,7 @@ func (k KongClient) getSpecFromBackend(ctx context.Context, backendURL string) (
for _, specPath := range k.specURLPaths {
endpoint := fmt.Sprintf("%s/%s", backendURL, strings.TrimPrefix(specPath, "/"))

spec, err := k.getSpec(ctx, endpoint)
spec, err := k.getSpec(ctx, endpoint, false)
if err != nil {
return nil, err
}
Expand All @@ -180,7 +233,7 @@ func (k KongClient) getSpecFromBackend(ctx context.Context, backendURL string) (
return nil, nil
}

func (k KongClient) getSpec(ctx context.Context, endpoint string) ([]byte, error) {
func (k KongClient) getSpec(ctx context.Context, endpoint string, fromDevPortal bool) ([]byte, error) {
ctxTimeout, cancel := context.WithTimeout(ctx, k.clientTimeout)
defer cancel()

Expand All @@ -198,12 +251,25 @@ func (k KongClient) getSpec(ctx context.Context, endpoint string) ([]byte, error
return nil, nil
}

specContent, err := io.ReadAll(res.Body)
data, err := io.ReadAll(res.Body)
if err != nil {
k.logger.WithError(err).Error("failed to read body")
return nil, err
}

var specContent []byte
if fromDevPortal {
kongServiceSpec := &KongServiceSpec{}
err = json.Unmarshal(data, kongServiceSpec)
if err != nil {
k.logger.WithError(err).Error("failed to unmarshal")
return nil, err
}
specContent = []byte(kongServiceSpec.Contents)
} else {
specContent = data
}

specParser := apic.NewSpecResourceParser(specContent, "")
err = specParser.Parse()
if err != nil {
Expand Down

0 comments on commit 15ffe60

Please sign in to comment.