Skip to content

Commit

Permalink
fix: do not fetch kong version when running validate
Browse files Browse the repository at this point in the history
decK used to fetch the running Kong version in order to gate
route regex patterns validation. This is problematic in
the case users don't have access to the `/` endpoint, which
is the one used to fetch the version of the runtime.

This commit removes the need of fetching the Kong version
entirely by relying on the `_format_version` field from the
config file instead.
  • Loading branch information
GGabriele committed Mar 20, 2024
1 parent 2af58c0 commit a038861
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 64 deletions.
55 changes: 26 additions & 29 deletions cmd/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,18 @@ import (
"sort"

"github.com/blang/semver/v4"
"github.com/kong/deck/utils"
"github.com/kong/go-database-reconciler/pkg/cprint"
"github.com/kong/go-database-reconciler/pkg/diff"
"github.com/kong/go-database-reconciler/pkg/dump"
"github.com/kong/go-database-reconciler/pkg/file"
"github.com/kong/go-database-reconciler/pkg/state"
"github.com/kong/go-database-reconciler/pkg/utils"
reconcilerUtils "github.com/kong/go-database-reconciler/pkg/utils"
"github.com/kong/go-kong/kong"
"github.com/spf13/cobra"
)

const (
exitCodeDiffDetection = 2
defaultFormatVersion = "1.1"
formatVersion30 = "3.0"
)
const exitCodeDiffDetection = 2

var (
dumpConfig dump.Config
Expand All @@ -52,7 +49,7 @@ func getMode(targetContent *file.Content) mode {
}

// workspaceExists checks if workspace exists in Kong.
func workspaceExists(ctx context.Context, config utils.KongClientConfig, workspaceName string) (bool, error) {
func workspaceExists(ctx context.Context, config reconcilerUtils.KongClientConfig, workspaceName string) (bool, error) {
rootConfig := config.ForWorkspace("")
if workspaceName == "" {
// default workspace always exists
Expand All @@ -64,7 +61,7 @@ func workspaceExists(ctx context.Context, config utils.KongClientConfig, workspa
return true, nil
}

rootClient, err := utils.GetKongClient(rootConfig)
rootClient, err := reconcilerUtils.GetKongClient(rootConfig)
if err != nil {
return false, err
}
Expand Down Expand Up @@ -180,13 +177,13 @@ func syncMain(ctx context.Context, filenames []string, dry bool, parallelism,
dumpConfig.KonnectControlPlane = konnectControlPlane
}

rootClient, err := utils.GetKongClient(rootConfig)
rootClient, err := reconcilerUtils.GetKongClient(rootConfig)
if err != nil {
return err
}

// prepare to read the current state from Kong
var wsConfig utils.KongClientConfig
var wsConfig reconcilerUtils.KongClientConfig
workspaceName := getWorkspaceName(workspace, targetContent, enableJSONOutput)
wsConfig = rootConfig.ForWorkspace(workspaceName)

Expand All @@ -201,20 +198,20 @@ func syncMain(ctx context.Context, filenames []string, dry bool, parallelism,
return fmt.Errorf("reading Kong version: %w", err)
}
}
parsedKongVersion, err = utils.ParseKongVersion(kongVersion)
parsedKongVersion, err = reconcilerUtils.ParseKongVersion(kongVersion)
if err != nil {
return fmt.Errorf("parsing Kong version: %w", err)
}

if parsedKongVersion.GTE(utils.Kong300Version) &&
targetContent.FormatVersion != formatVersion30 {
if parsedKongVersion.GTE(reconcilerUtils.Kong300Version) &&
targetContent.FormatVersion != utils.FormatVersion30 {
formatVersion := targetContent.FormatVersion
if formatVersion == "" {
formatVersion = defaultFormatVersion
formatVersion = utils.DefaultFormatVersion
}
return fmt.Errorf(
"cannot apply '%s' config format version to Kong version 3.0 or above.\n"+
utils.UpgradeMessage, formatVersion)
reconcilerUtils.UpgradeMessage, formatVersion)
}

// TODO: instead of guessing the cobra command here, move the sendAnalytics
Expand All @@ -228,7 +225,7 @@ func syncMain(ctx context.Context, filenames []string, dry bool, parallelism,
}

if kongClient == nil {
kongClient, err = utils.GetKongClient(wsConfig)
kongClient, err = reconcilerUtils.GetKongClient(wsConfig)
if err != nil {
return err
}
Expand Down Expand Up @@ -275,7 +272,7 @@ func syncMain(ctx context.Context, filenames []string, dry bool, parallelism,
}
}

if utils.Kong340Version.LTE(parsedKongVersion) {
if reconcilerUtils.Kong340Version.LTE(parsedKongVersion) {
dumpConfig.IsConsumerGroupScopedPluginSupported = true
}

Expand Down Expand Up @@ -330,7 +327,7 @@ func syncMain(ctx context.Context, filenames []string, dry bool, parallelism,
ctx, currentState, targetState, dry, parallelism, delay, kongClient, mode == modeKonnect, enableJSONOutput)
if err != nil {
if enableJSONOutput {
var errs utils.ErrArray
var errs reconcilerUtils.ErrArray
if errors.As(err, &errs) {
jsonOutput.Errors = append(jsonOutput.Errors, errs.ErrorList()...)
} else {
Expand Down Expand Up @@ -365,7 +362,7 @@ func determineLookUpSelectorTagsConsumers(targetContent file.Content) ([]string,
if len(targetContent.Info.LookUpSelectorTags.Consumers) == 0 {
return nil, fmt.Errorf("global consumers specified but no global tags")
}
utils.RemoveDuplicates(&targetContent.Info.LookUpSelectorTags.Consumers)
reconcilerUtils.RemoveDuplicates(&targetContent.Info.LookUpSelectorTags.Consumers)
sort.Strings(targetContent.Info.LookUpSelectorTags.Consumers)
return targetContent.Info.LookUpSelectorTags.Consumers, nil

Expand All @@ -380,7 +377,7 @@ func determineLookUpSelectorTagsRoutes(targetContent file.Content) ([]string, er
if len(targetContent.Info.LookUpSelectorTags.Routes) == 0 {
return nil, fmt.Errorf("global routes specified but no global tags")
}
utils.RemoveDuplicates(&targetContent.Info.LookUpSelectorTags.Routes)
reconcilerUtils.RemoveDuplicates(&targetContent.Info.LookUpSelectorTags.Routes)
sort.Strings(targetContent.Info.LookUpSelectorTags.Routes)
return targetContent.Info.LookUpSelectorTags.Routes, nil

Expand All @@ -391,7 +388,7 @@ func determineLookUpSelectorTagsRoutes(targetContent file.Content) ([]string, er
func determineSelectorTag(targetContent file.Content, config dump.Config) ([]string, error) {
if targetContent.Info != nil {
if len(targetContent.Info.SelectorTags) > 0 {
utils.RemoveDuplicates(&targetContent.Info.SelectorTags)
reconcilerUtils.RemoveDuplicates(&targetContent.Info.SelectorTags)
if len(config.SelectorTags) > 0 {
sort.Strings(config.SelectorTags)
sort.Strings(targetContent.Info.SelectorTags)
Expand Down Expand Up @@ -446,7 +443,7 @@ func performDiff(ctx context.Context, currentState, targetState *state.KongState
printStats(stats)
}
if errs != nil {
return 0, utils.ErrArray{Errors: errs}
return 0, reconcilerUtils.ErrArray{Errors: errs}
}
totalOps := stats.CreateOps.Count() + stats.UpdateOps.Count() + stats.DeleteOps.Count()

Expand All @@ -466,14 +463,14 @@ func performDiff(ctx context.Context, currentState, targetState *state.KongState
return int(totalOps), nil
}

func fetchKongVersion(ctx context.Context, config utils.KongClientConfig) (string, error) {
func fetchKongVersion(ctx context.Context, config reconcilerUtils.KongClientConfig) (string, error) {
var version string

workspace := config.Workspace

// remove workspace to be able to call top-level / endpoint
config.Workspace = ""
client, err := utils.GetKongClient(config)
client, err := reconcilerUtils.GetKongClient(config)
if err != nil {
return "", err
}
Expand All @@ -484,7 +481,7 @@ func fetchKongVersion(ctx context.Context, config utils.KongClientConfig) (strin
}
// try with workspace path
req, err := http.NewRequest("GET",
utils.CleanAddress(config.Address)+"/"+workspace+"/kong",
reconcilerUtils.CleanAddress(config.Address)+"/"+workspace+"/kong",
nil)
if err != nil {
return "", err
Expand All @@ -509,7 +506,7 @@ func validateNoArgs(_ *cobra.Command, args []string) error {
return nil
}

func checkForRBACResources(content utils.KongRawState,
func checkForRBACResources(content reconcilerUtils.KongRawState,
rbacResourcesOnly bool,
) error {
proxyConfig := containsProxyConfiguration(content)
Expand All @@ -527,7 +524,7 @@ func checkForRBACResources(content utils.KongRawState,
return nil
}

func containsProxyConfiguration(content utils.KongRawState) bool {
func containsProxyConfiguration(content reconcilerUtils.KongRawState) bool {
return len(content.Services) != 0 ||
len(content.Routes) != 0 ||
len(content.Plugins) != 0 ||
Expand All @@ -537,7 +534,7 @@ func containsProxyConfiguration(content utils.KongRawState) bool {
len(content.Consumers) != 0
}

func containsRBACConfiguration(content utils.KongRawState) bool {
func containsRBACConfiguration(content reconcilerUtils.KongRawState) bool {
return len(content.RBACRoles) != 0
}

Expand All @@ -556,7 +553,7 @@ func sendAnalytics(cmd, kongVersion string, mode mode) error {
case modeLocal:
modeStr = "local"
}
return utils.SendAnalytics(cmd, VERSION, kongVersion, modeStr)
return reconcilerUtils.SendAnalytics(cmd, VERSION, kongVersion, modeStr)
}

func inKonnectMode(targetContent *file.Content) bool {
Expand Down
63 changes: 34 additions & 29 deletions cmd/gateway_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import (
"fmt"
"os"

"github.com/blang/semver/v4"
"github.com/kong/deck/utils"
"github.com/kong/deck/validate"
"github.com/kong/go-database-reconciler/pkg/dump"
"github.com/kong/go-database-reconciler/pkg/file"
"github.com/kong/go-database-reconciler/pkg/state"
"github.com/kong/go-database-reconciler/pkg/utils"
reconcilerUtils "github.com/kong/go-database-reconciler/pkg/utils"
"github.com/kong/go-kong/kong"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -103,7 +105,7 @@ func executeValidate(cmd *cobra.Command, _ []string) error {
}

if validateOnline {
if errs := validateWithKong(ctx, kongClient, ks); len(errs) != 0 {
if errs := validateWithKong(ctx, kongClient, ks, targetContent.FormatVersion); len(errs) != 0 {
return validate.ErrorsWrapper{Errors: errs}
}
}
Expand Down Expand Up @@ -214,13 +216,16 @@ this command unless --online flag is used.
return validateCmd
}

func validateWithKong(ctx context.Context, kongClient *kong.Client, ks *state.KongState) []error {
// make sure we are able to connect to Kong
kongVersion, err := fetchKongVersion(ctx, rootConfig.ForWorkspace(validateWorkspace))
if err != nil {
return []error{fmt.Errorf("couldn't fetch Kong version: %w", err)}
}
parsedKongVersion, err := utils.ParseKongVersion(kongVersion)
func validateWithKong(
ctx context.Context,
kongClient *kong.Client,
ks *state.KongState,
formatVersion string,
) []error {
if formatVersion == "" {
formatVersion = utils.DefaultFormatVersion
}
parsedFormatVersion, err := semver.ParseTolerant(formatVersion)
if err != nil {
return []error{fmt.Errorf("parsing Kong version: %w", err)}
}
Expand All @@ -232,7 +237,7 @@ func validateWithKong(ctx context.Context, kongClient *kong.Client, ks *state.Ko
RBACResourcesOnly: validateCmdRBACResourcesOnly,
}
validator := validate.NewValidator(opts)
return validator.Validate(parsedKongVersion)
return validator.Validate(parsedFormatVersion)
}

func getKongClient(ctx context.Context, targetContent *file.Content) (*kong.Client, error) {
Expand All @@ -250,7 +255,7 @@ func getKongClient(ctx context.Context, targetContent *file.Content) (*kong.Clie
}

wsConfig := rootConfig.ForWorkspace(workspaceName)
kongClient, err := utils.GetKongClient(wsConfig)
kongClient, err := reconcilerUtils.GetKongClient(wsConfig)
if err != nil {
return nil, err
}
Expand All @@ -263,58 +268,58 @@ func getKongClient(ctx context.Context, targetContent *file.Content) (*kong.Clie
func ensureGetAllMethods() error {
// let's make sure ASAP that all resources have the expected GetAll method
dummyEmptyState, _ := state.NewKongState()
if _, err := utils.CallGetAll(dummyEmptyState.Services); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.Services); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.ACLGroups); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.ACLGroups); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.BasicAuths); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.BasicAuths); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.CACertificates); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.CACertificates); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.Certificates); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.Certificates); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.Consumers); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.Consumers); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.Documents); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.Documents); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.HMACAuths); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.HMACAuths); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.JWTAuths); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.JWTAuths); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.KeyAuths); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.KeyAuths); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.Oauth2Creds); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.Oauth2Creds); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.Plugins); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.Plugins); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.Routes); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.Routes); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.SNIs); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.SNIs); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.Targets); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.Targets); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.Upstreams); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.Upstreams); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.RBACEndpointPermissions); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.RBACEndpointPermissions); err != nil {
return err
}
if _, err := utils.CallGetAll(dummyEmptyState.RBACRoles); err != nil {
if _, err := reconcilerUtils.CallGetAll(dummyEmptyState.RBACRoles); err != nil {
return err
}
return nil
Expand Down
6 changes: 6 additions & 0 deletions utils/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package utils

const (
DefaultFormatVersion = "1.1"
FormatVersion30 = "3.0"
)
Loading

0 comments on commit a038861

Please sign in to comment.