diff --git a/cmd/common.go b/cmd/common.go index d24833619..1eeb78567 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -152,20 +152,7 @@ func syncMain(ctx context.Context, filenames []string, dry bool, parallelism, } return fmt.Errorf( "cannot apply '%s' config format version to Kong version 3.0 or above.\n"+ - "Please upgrade your configuration to account for 3.0\n"+ - "breaking changes using the following command:\n\n"+ - "deck convert --from kong-gateway-2.x --to kong-gateway-3.x\n\n"+ - "This command performs the following changes:\n"+ - " - upgrade the `_format_version` value to `3.0`\n"+ - " - add the `~` prefix to all routes' paths containing a regex-pattern\n\n"+ - "These changes may not be correct or exhaustive enough.\n"+ - "It is strongly recommended to perform a manual audit\n"+ - "of the updated configuration file before applying\n"+ - "the configuration in production. Incorrect changes will result in\n"+ - "unintended traffic routing by Kong Gateway.\n\n"+ - - "For more information about this and related changes,\n"+ - "please visit: https://docs.konghq.com/deck/latest/3.0-upgrade", formatVersion) + utils.UpgradeMessage, formatVersion) } // TODO: instead of guessing the cobra command here, move the sendAnalytics diff --git a/convert/convert.go b/convert/convert.go index c328773f8..49843efd9 100644 --- a/convert/convert.go +++ b/convert/convert.go @@ -82,13 +82,39 @@ func convertKongGateway2xTo3x(input *file.Content, filename string) (*file.Conte outputContent := input.DeepCopy() convertedRoutes := []*file.FRoute{} + changedRoutes := []string{} for _, service := range outputContent.Services { for _, route := range service.Routes { - convertedRoutes = append(convertedRoutes, migrateRoutesPathFieldPre300(route, filename)) + route, hasChanged := migrateRoutesPathFieldPre300(route) + convertedRoutes = append(convertedRoutes, route) + if hasChanged { + if route.ID != nil { + changedRoutes = append(changedRoutes, *route.ID) + } else { + changedRoutes = append(changedRoutes, *route.Name) + } + } } service.Routes = convertedRoutes } + if len(changedRoutes) > 0 { + changedRoutesLen := len(changedRoutes) + // do not consider more than 10 sample routes to print out. + if changedRoutesLen > 10 { + changedRoutes = changedRoutes[:10] + } + cprint.UpdatePrintf( + "From the '%s' config file,\n"+ + "%d unsupported routes' paths format with Kong version 3.0\n"+ + "or above were detected. Some of these routes are (not an exhaustive list):\n\n"+ + "%s\n\n"+ + "Kong gateway versions 3.0 and above require that regular expressions\n"+ + "start with a '~' character to distinguish from simple prefix match.\n"+ + "In order to make these paths compatible with 3.x, a '~' prefix has been added.\n\n", + filename, changedRoutesLen, strings.Join(changedRoutes, "\n")) + } + cprint.UpdatePrintf( "From the '%s' config file,\n"+ "the _format_version field has been migrated from '%s' to '%s'.\n"+ @@ -102,31 +128,15 @@ func convertKongGateway2xTo3x(input *file.Content, filename string) (*file.Conte return outputContent, nil } -func migrateRoutesPathFieldPre300(route *file.FRoute, filename string) *file.FRoute { - changedPaths := []string{} +func migrateRoutesPathFieldPre300(route *file.FRoute) (*file.FRoute, bool) { + var hasChanged bool for _, path := range route.Paths { if !strings.HasPrefix(*path, "~/") && utils.IsPathRegexLike(*path) { - changedPaths = append(changedPaths, *path) *path = "~" + *path + hasChanged = true } } - if len(changedPaths) > 0 { - changedPathsLen := len(changedPaths) - // do not consider more than 3 sample routes to print out. - if changedPathsLen > 3 { - changedPaths = changedPaths[:3] - } - cprint.UpdatePrintf( - "From the '%s' config file,\n"+ - "%d routes paths matching an unsupported regex pattern usage\n"+ - "with Kong version 3.0 or above were detected\n"+ - "(e.g. %s).\n\n"+ - "Kong gateway versions 3.0 and above require that regular expressions\n"+ - "start with a '~' character to distinguish from simple prefix match.\n"+ - "In order to make these paths compatible with 3.x, a '~' prefix has been added.\n\n", - filename, changedPathsLen, strings.Join(changedPaths, ", ")) - } - return route + return route, hasChanged } func convertKongGatewayToKonnect(input *file.Content) (*file.Content, error) { diff --git a/file/builder.go b/file/builder.go index edb093ad2..3abce7ff6 100644 --- a/file/builder.go +++ b/file/builder.go @@ -609,6 +609,24 @@ func (b *stateBuilder) routes() { return } } + + // check routes' paths format + if b.checkRoutePaths { + unsupportedRoutes := []string{} + allRoutes, err := b.intermediate.Routes.GetAll() + if err != nil { + b.err = err + return + } + for _, r := range allRoutes { + if utils.HasPathsWithRegex300AndAbove(r.Route) { + unsupportedRoutes = append(unsupportedRoutes, *r.Route.ID) + } + } + if len(unsupportedRoutes) > 0 { + utils.PrintRouteRegexWarning(unsupportedRoutes) + } + } } func (b *stateBuilder) enterprise() { @@ -799,10 +817,6 @@ func (b *stateBuilder) ingestRoute(r FRoute) error { return err } - if b.checkRoutePaths { - utils.CheckRoutePaths300AndAbove(r.Route) - } - // plugins for the route var plugins []FPlugin for _, p := range r.Plugins { diff --git a/tests/integration/sync_test.go b/tests/integration/sync_test.go index 29d325d80..7f68afe4c 100644 --- a/tests/integration/sync_test.go +++ b/tests/integration/sync_test.go @@ -1803,20 +1803,7 @@ func Test_Sync_Unsupported_Formats(t *testing.T) { kongFile: "testdata/sync/001-create-a-service/kong.yaml", expectedError: errors.New( "cannot apply '1.1' config format version to Kong version 3.0 or above.\n" + - "Please upgrade your configuration to account for 3.0\n" + - "breaking changes using the following command:\n\n" + - "deck convert --from kong-gateway-2.x --to kong-gateway-3.x\n\n" + - "This command performs the following changes:\n" + - " - upgrade the `_format_version` value to `3.0`\n" + - " - add the `~` prefix to all routes' paths containing a regex-pattern\n\n" + - "These changes may not be correct or exhaustive enough.\n" + - "It is strongly recommended to perform a manual audit\n" + - "of the updated configuration file before applying\n" + - "the configuration in production. Incorrect changes will result in\n" + - "unintended traffic routing by Kong Gateway.\n\n" + - - "For more information about this and related changes,\n" + - "please visit: https://docs.konghq.com/deck/latest/3.0-upgrade"), + utils.UpgradeMessage), }, } for _, tc := range tests { diff --git a/utils/utils.go b/utils/utils.go index 05ffe9fb6..e00f37c6b 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -23,6 +23,21 @@ var ( Kong300Version = semver.MustParse("3.0.0") ) +var UpgradeMessage = "Please upgrade your configuration to account for 3.0\n" + + "breaking changes using the following command:\n\n" + + "deck convert --from kong-gateway-2.x --to kong-gateway-3.x\n\n" + + "This command performs the following changes:\n" + + " - upgrade the `_format_version` value to `3.0`\n" + + " - add the `~` prefix to all routes' paths containing a regex-pattern\n\n" + + "These changes may not be correct or exhaustive enough.\n" + + "It is strongly recommended to perform a manual audit\n" + + "of the updated configuration file before applying\n" + + "the configuration in production. Incorrect changes will result in\n" + + "unintended traffic routing by Kong Gateway.\n\n" + + + "For more information about this and related changes,\n" + + "please visit: https://docs.konghq.com/deck/latest/3.0-upgrade\n\n" + // IsPathRegexLike checks if a path string contains a regex pattern. func IsPathRegexLike(path string) bool { return pathRegexPattern.MatchString(path) @@ -190,27 +205,29 @@ func ConfigFilesInDir(dir string) ([]string, error) { return res, nil } -// CheckRoutePaths300AndAbove checks routes' paths format and prints out -// a warning if regex-like patters without the '~' prefix are found. -func CheckRoutePaths300AndAbove(route kong.Route) { - pathsWarnings := []string{} +// HasPathsWithRegex300AndAbove checks routes' paths format and returns true +// if these math a regex-pattern without a '~' prefix. +func HasPathsWithRegex300AndAbove(route kong.Route) bool { for _, p := range route.Paths { if strings.HasPrefix(*p, "~/") || !IsPathRegexLike(*p) { continue } - pathsWarnings = append(pathsWarnings, *p) + return true } - if len(pathsWarnings) > 0 { - cprint.UpdatePrintf( - "In Route '%s', a path with regular expression was detected.\n"+ - "In Kong Gateway versions 3.0 and above, all paths that use regular expressions \n"+ - "must be prefixed with a ~ character. Without the ~ prefix, regular expression \n"+ - "based paths will not be matched and processed correctly. \n\n"+ - "Please run the following command to upgrade your config: \n\n"+ - "deck convert --from kong-gateway-2.x --to kong-gateway-3.x "+ - "--input-file --output-file \n\n"+ - "Please refer to the following document for further details:\n"+ - "https://docs.konghq.com/deck/latest/3.0-upgrade.\n\n", - *route.ID) + return false +} + +// PrintRouteRegexWarning prints out a warning about 3.x routes' path usage. +func PrintRouteRegexWarning(unsupportedRoutes []string) { + unsupportedRoutesLen := len(unsupportedRoutes) + // do not consider more than 10 sample routes to print out. + if unsupportedRoutesLen > 10 { + unsupportedRoutes = unsupportedRoutes[:10] } + cprint.UpdatePrintf( + "%d unsupported routes' paths format with Kong version 3.0\n"+ + "or above were detected. Some of these routes are (not an exhaustive list):\n\n"+ + "%s\n\n"+UpgradeMessage, + unsupportedRoutesLen, strings.Join(unsupportedRoutes, "\n"), + ) } diff --git a/validate/validate.go b/validate/validate.go index cc95c91f7..939549229 100644 --- a/validate/validate.go +++ b/validate/validate.go @@ -186,7 +186,13 @@ func (v *Validator) Validate(kongVersion semver.Version) []error { func validate3xRoutes(routes *state.RoutesCollection) { results, _ := routes.GetAll() + unsupportedRoutes := []string{} for _, r := range results { - utils.CheckRoutePaths300AndAbove(r.Route) + if utils.HasPathsWithRegex300AndAbove(r.Route) { + unsupportedRoutes = append(unsupportedRoutes, *r.Route.ID) + } + } + if len(unsupportedRoutes) > 0 { + utils.PrintRouteRegexWarning(unsupportedRoutes) } }