Skip to content

Commit

Permalink
feat: add capability to convert from 2.x to 3.x format
Browse files Browse the repository at this point in the history
  • Loading branch information
GGabriele committed Sep 14, 2022
1 parent df1e1a9 commit db7331b
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 2 deletions.
4 changes: 2 additions & 2 deletions cmd/convert.go
Expand Up @@ -54,8 +54,8 @@ can be converted into a 'konnect' configuration file.`,
},
}

sourceFormats := []convert.Format{convert.FormatKongGateway}
destinationFormats := []convert.Format{convert.FormatKonnect}
sourceFormats := []convert.Format{convert.FormatKongGateway, convert.FormatKongGateway2x}
destinationFormats := []convert.Format{convert.FormatKonnect, convert.FormatKongGateway3x}
convertCmd.Flags().StringVar(&convertCmdSourceFormat, "from", "",
fmt.Sprintf("format of the source file, allowed formats: %v", sourceFormats))
convertCmd.Flags().StringVar(&convertCmdDestinationFormat, "to", "",
Expand Down
58 changes: 58 additions & 0 deletions convert/convert.go
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"strings"

"github.com/kong/deck/cprint"
"github.com/kong/deck/file"
"github.com/kong/deck/utils"
"github.com/kong/go-kong/kong"
Expand All @@ -16,6 +17,10 @@ const (
FormatKongGateway Format = "kong-gateway"
// FormatKonnect represents the Konnect format.
FormatKonnect Format = "konnect"
// FormatKongGateway2x represents the Kong gateway 2.x format.
FormatKongGateway2x Format = "kong-gateway-2.x"
// FormatKongGateway3x represents the Kong gateway 3.x format.
FormatKongGateway3x Format = "kong-gateway-3.x"
)

// AllFormats contains all available formats.
Expand All @@ -28,6 +33,10 @@ func ParseFormat(key string) (Format, error) {
return FormatKongGateway, nil
case FormatKonnect:
return FormatKonnect, nil
case FormatKongGateway2x:
return FormatKongGateway2x, nil
case FormatKongGateway3x:
return FormatKongGateway3x, nil
default:
return "", fmt.Errorf("invalid format: '%v'", key)
}
Expand All @@ -50,6 +59,11 @@ func Convert(inputFilename, outputFilename string, from, to Format) error {
if err != nil {
return err
}
case from == FormatKongGateway2x && to == FormatKongGateway3x:
outputContent, err = convertKongGateway2xTo3x(inputContent)
if err != nil {
return err
}
default:
return fmt.Errorf("cannot convert from '%s' to '%s' format", from, to)
}
Expand All @@ -61,6 +75,50 @@ func Convert(inputFilename, outputFilename string, from, to Format) error {
return nil
}

func convertKongGateway2xTo3x(input *file.Content) (*file.Content, error) {
if input == nil {
return nil, fmt.Errorf("input content is nil")
}
outputContent := input.DeepCopy()

convertedRoutes := []*file.FRoute{}
for _, service := range outputContent.Services {
for _, route := range service.Routes {
convertedRoutes = append(convertedRoutes, migrateRoutesPathFieldPre300(route))
}
service.Routes = convertedRoutes
}

cprint.UpdatePrintf(
"From the config file, the _format_version field has been migrated from '%s' to '%s'.\n"+
"These automatic changes may not be fully correct or exhaustive, so please\n"+
"take the time to perform a manual audit of the config file.\n\n"+
"For related information, please visit: https://docs.konghq.com/gateway/latest/\n",
outputContent.FormatVersion, "3.0")
outputContent.FormatVersion = "3.0"
return outputContent, nil
}

func migrateRoutesPathFieldPre300(route *file.FRoute) *file.FRoute {
changedPaths := []string{}
for _, path := range route.Paths {
if !strings.HasPrefix(*path, "~/") && utils.IsPathRegexLike(*path) {
changedPaths = append(changedPaths, *path)
*path = "~" + *path
}
}
if len(changedPaths) > 0 {
cprint.UpdatePrintf(
"From the config file, for the route '%s', a regex pattern usage was detected\n"+
"for the '%s' paths in the 'paths' field.\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",
*route.Name, strings.Join(changedPaths, ", "))
}
return route
}

func convertKongGatewayToKonnect(input *file.Content) (*file.Content, error) {
if input == nil {
return nil, fmt.Errorf("input content is nil")
Expand Down
47 changes: 47 additions & 0 deletions convert/convert_test.go
Expand Up @@ -28,6 +28,22 @@ func TestParseFormat(t *testing.T) {
want: FormatKongGateway,
wantErr: false,
},
{
name: "parses valid values",
args: args{
key: "kong-gateway-2.x",
},
want: FormatKongGateway2x,
wantErr: false,
},
{
name: "parses valid values",
args: args{
key: "kong-gateway-3.x",
},
want: FormatKongGateway3x,
wantErr: false,
},
{
name: "parses values in a case-insensitive manner",
args: args{
Expand Down Expand Up @@ -161,6 +177,15 @@ func Test_Convert(t *testing.T) {
},
wantErr: true,
},
{
name: "errors out due to invalid conversion",
args: args{
inputFilename: "testdata/3/input.yaml",
fromFormat: FormatKongGateway3x,
toFormat: FormatKongGateway2x,
},
wantErr: true,
},
{
name: "errors out when a nameless service is present in the input",
args: args{
Expand Down Expand Up @@ -190,6 +215,28 @@ func Test_Convert(t *testing.T) {
},
wantErr: false,
},
{
name: "converts from Kong Gateway 2.x to Kong Gateway 3.x format",
args: args{
inputFilename: "testdata/3/input.yaml",
outputFilename: "testdata/3/output.yaml",
expectedOutputFilename: "testdata/3/output-expected.yaml",
fromFormat: FormatKongGateway2x,
toFormat: FormatKongGateway3x,
},
wantErr: false,
},
{
name: "converts from Kong Gateway 2.x to Kong Gateway 3.x format (no _format_version input)",
args: args{
inputFilename: "testdata/4/input.yaml",
outputFilename: "testdata/4/output.yaml",
expectedOutputFilename: "testdata/4/output-expected.yaml",
fromFormat: FormatKongGateway2x,
toFormat: FormatKongGateway3x,
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
9 changes: 9 additions & 0 deletions convert/testdata/3/input.yaml
@@ -0,0 +1,9 @@
services:
- name: svc1
host: mockbin.org
path: /status/200
routes:
- name: r1
paths:
- /status/\d+
- /code/\d+
10 changes: 10 additions & 0 deletions convert/testdata/3/output-expected.yaml
@@ -0,0 +1,10 @@
_format_version: "3.0"
services:
- name: svc1
host: mockbin.org
path: /status/200
routes:
- name: r1
paths:
- ~/status/\d+
- ~/code/\d+
10 changes: 10 additions & 0 deletions convert/testdata/3/output.yaml
@@ -0,0 +1,10 @@
_format_version: "3.0"
services:
- host: mockbin.org
name: svc1
path: /status/200
routes:
- name: r1
paths:
- ~/status/\d+
- ~/code/\d+
10 changes: 10 additions & 0 deletions convert/testdata/4/input.yaml
@@ -0,0 +1,10 @@
_format_version: "1.1"
services:
- name: svc1
host: mockbin.org
path: /status/200
routes:
- name: r1
paths:
- /status/\d+
- /code/\d+
10 changes: 10 additions & 0 deletions convert/testdata/4/output-expected.yaml
@@ -0,0 +1,10 @@
_format_version: "3.0"
services:
- name: svc1
host: mockbin.org
path: /status/200
routes:
- name: r1
paths:
- ~/status/\d+
- ~/code/\d+
10 changes: 10 additions & 0 deletions convert/testdata/4/output.yaml
@@ -0,0 +1,10 @@
_format_version: "3.0"
services:
- host: mockbin.org
name: svc1
path: /status/200
routes:
- name: r1
paths:
- ~/status/\d+
- ~/code/\d+

0 comments on commit db7331b

Please sign in to comment.