Skip to content

Commit

Permalink
feat: implement new convert command
Browse files Browse the repository at this point in the history
  • Loading branch information
hbagdi committed Apr 20, 2021
1 parent 6ede1a8 commit f44bf6a
Show file tree
Hide file tree
Showing 9 changed files with 761 additions and 4 deletions.
60 changes: 60 additions & 0 deletions cmd/convert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package cmd

import (
"fmt"

"github.com/kong/deck/convert"
"github.com/spf13/cobra"
)

var (
convertCmdSourceFormat string
convertCmdDestinationFormat string
convertCmdInputFile string
convertCmdOutputFile string
)

// convertCmd represents the convert command
var convertCmd = &cobra.Command{
Use: "convert",
Short: "Convert files in one format to another format",
Long: `Convert command converts files representing configuration in one format
to another compatible format.
and usage of using your command. For example: a configuration for 'kong-gateway'
can be converted into 'konnect' configuration file.`,
Args: validateNoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
sourceFormat, err := convert.ParseFormat(convertCmdSourceFormat)
if err != nil {
return err
}
destinationFormat, err := convert.ParseFormat(convertCmdDestinationFormat)
if err != nil {
return err
}

if yes, err := confirmFileOverwrite(convertCmdOutputFile, "", false); err != nil {
return err
} else if !yes {
return nil
}

err = convert.Convert(convertCmdInputFile, convertCmdOutputFile, sourceFormat, destinationFormat)
if err != nil {
return fmt.Errorf("converting file: %v", err)
}
return nil
},
}

func init() {
convertCmd.Flags().StringVar(&convertCmdSourceFormat, "from", "",
fmt.Sprintf("format of the source file, allowed formats:%v", convert.AllFormats))
convertCmd.Flags().StringVar(&convertCmdDestinationFormat, "to", "",
fmt.Sprintf("desired format of the output, allowed formats:%v", convert.AllFormats))
convertCmd.Flags().StringVar(&convertCmdInputFile, "input-file", "",
"file containing configuration that needs to be converted. Use '-' to read from stdin.")
convertCmd.Flags().StringVar(&convertCmdOutputFile, "output-file", "",
"file to which to write configuration after conversion. Use '-' to write to stdout.")
rootCmd.AddCommand(convertCmd)
}
118 changes: 118 additions & 0 deletions convert/convert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package convert

import (
"fmt"
"strings"

"github.com/kong/deck/file"
"github.com/kong/deck/utils"
"github.com/kong/go-kong/kong"
)

type Format string

const (
FormatKongGateway Format = "kong-gateway"
FormatKonnect Format = "konnect"
)

var (
AllFormats = []Format{FormatKongGateway, FormatKonnect}

conversions = map[Format]map[Format]bool{
FormatKongGateway: {
FormatKonnect: true,
},
}
)

func validConversion(from, to Format) (bool, error) {
if fromMap, ok := conversions[from]; ok {
if _, ok := fromMap[to]; ok {
return ok, nil
}
}

return false, fmt.Errorf("cannot convert from '%s' to '%s' format", from, to)
}

func ParseFormat(key string) (Format, error) {
format := Format(strings.ToLower(key))
switch format {
case FormatKongGateway:
return FormatKongGateway, nil
case FormatKonnect:
return FormatKonnect, nil
default:
return "", fmt.Errorf("invalid format: '%v'", key)
}
}

func Convert(inputFilename, outputFilename string, from, to Format) error {
if valid, err := validConversion(from, to); !valid {
return err
}

key := from + to
switch key {
case FormatKongGateway + FormatKonnect:
return convertKongGatewayToKonnect(inputFilename, outputFilename)
default:
return fmt.Errorf("cannot convert from '%s' to '%s' format", from, to)
}
}

func convertKongGatewayToKonnect(inputFilename, outputFilename string) error {
inputContent, err := file.GetContentFromFiles([]string{inputFilename})
if err != nil {
return err
}

for _, service := range inputContent.Services {
servicePackage, err := kongServiceToKonnectServicePackage(service)
if err != nil {
return err
}
inputContent.ServicePackages = append(inputContent.ServicePackages, servicePackage)
}
// Remove Kong Services from the file because all of them have been converted
// into Service packages
inputContent.Services = nil

// all other entities are left as is

if err := file.WriteContentToFile(inputContent, outputFilename, file.YAML); err != nil {
return err
}
return nil
}

func kongServiceToKonnectServicePackage(service file.FService) (file.FServicePackage, error) {
var serviceName string
if service.Name == nil {
return file.FServicePackage{}, fmt.Errorf("kong service with id '%s' doesn't have a name,"+
"all services must be named to convert them from %s to %s format",
*service.ID, FormatKongGateway, FormatKonnect)
}
serviceName = *service.Name
// Kong service MUST contain an ID and no name in Konnect representation
service.Name = nil
service.ID = kong.String(utils.UUID())

// convert Kong Service to a Service Package
return file.FServicePackage{
Name: &serviceName,
Description: kong.String("placeholder description for " + serviceName + " service package"),
Versions: []file.FServiceVersion{
{
Version: kong.String("v1"),
Implementation: &file.Implementation{
Type: utils.ImplementationTypeKongGateway,
Kong: &file.Kong{
Service: &service,
},
},
},
},
}, nil
}
Loading

0 comments on commit f44bf6a

Please sign in to comment.