Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add kong2tf command #1391

Merged
merged 7 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ docs/cli-docs/

# generated test 'actuals'
kong2kic/testdata/**/*-actual.*
kong2tf/testdata/**/*-actual.*
kong2tf/terraform
95 changes: 95 additions & 0 deletions cmd/file_kong2tf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package cmd

import (
"fmt"
"log"

"github.com/kong/deck/kong2tf"
"github.com/kong/go-apiops/filebasics"
"github.com/kong/go-apiops/logbasics"
"github.com/kong/go-database-reconciler/pkg/file"
"github.com/spf13/cobra"
)

var (
cmdKong2TfInputFilename string
cmdKong2TfOutputFilename string
cmdKong2TfGenerateImportsForControlPlaneID string
cmdKong2TfIgnoreCredentialChanges bool
)

// Executes the CLI command "kong2Tf"
func executeKong2Tf(cmd *cobra.Command, _ []string) error {
_ = sendAnalytics("file-kong2Tf", "", modeLocal)
var (
result string
err error
)

verbosity, _ := cmd.Flags().GetInt("verbose")
logbasics.Initialize(log.LstdFlags, verbosity)

logbasics.Info("Starting execution of executeKong2Tf")

inputContent, err := file.GetContentFromFiles([]string{cmdKong2TfInputFilename}, false)
if err != nil {
log.Printf("Error reading input file '%s'; %v", cmdKong2TfInputFilename, err)
return fmt.Errorf("failed reading input file '%s'; %w", cmdKong2TfInputFilename, err)
}
logbasics.Info("Successfully read input file '%s'", cmdKong2TfInputFilename)

logbasics.Info("Converting Kong configuration to Terraform")

var generateImportsForControlPlaneID *string
if cmdKong2TfGenerateImportsForControlPlaneID != "" {
generateImportsForControlPlaneID = &cmdKong2TfGenerateImportsForControlPlaneID
}
result, err = kong2tf.Convert(inputContent, generateImportsForControlPlaneID, cmdKong2TfIgnoreCredentialChanges)
if err != nil {
log.Printf("Error converting Kong configuration to Terraform; %v", err)
return fmt.Errorf("failed converting Kong configuration to Terraform; %w", err)
}
logbasics.Info("Successfully converted Kong configuration to Terraform")

logbasics.Info("Writing output to file '%s'", cmdKong2TfOutputFilename)
err = filebasics.WriteFile(cmdKong2TfOutputFilename, []byte(result))
if err != nil {
log.Printf("Error writing output to file '%s'; %v", cmdKong2TfOutputFilename, err)
return err
}
logbasics.Info("Successfully wrote output to file '%s'", cmdKong2TfOutputFilename)

logbasics.Info("Finished execution of executeKong2Tf")
return nil
}

//
//
// Define the CLI data for the kong2Tf command
//
//

func newKong2TfCmd() *cobra.Command {
kong2TfCmd := &cobra.Command{
Use: "kong2tf",
Short: "Convert Kong configuration files to Terraform resources",
Long: `Convert Kong configuration files to Terraform resources.

The kong2tf subcommand transforms Kong Gateway entities in deck format,
into Terraform resources.`,
RunE: executeKong2Tf,
Args: cobra.NoArgs,
}

kong2TfCmd.Flags().StringVarP(&cmdKong2TfInputFilename, "state", "s", "-",
"decK file to process. Use - to read from stdin.")
kong2TfCmd.Flags().StringVarP(&cmdKong2TfOutputFilename, "output-file", "o", "-",
"Output file to write. Use - to write to stdout.")
kong2TfCmd.Flags().StringVarP(&cmdKong2TfGenerateImportsForControlPlaneID,
"generate-imports-for-control-plane-id", "g", "", "Generate terraform import statements for the control plane ID.")
kong2TfCmd.Flags().BoolVar(&cmdKong2TfIgnoreCredentialChanges, "ignore-credential-changes", false,
"Enable flag to add a 'lifecycle' block to each consumer credential, "+
"that ignores any changes from local to remote state.")

return kong2TfCmd
}
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ It can be used to export, import, or sync entities to Kong.`,
fileCmd.AddCommand(newConvertCmd(false))
fileCmd.AddCommand(newValidateCmd(false, false)) // file-based validation
fileCmd.AddCommand(newKong2KicCmd())
fileCmd.AddCommand(newKong2TfCmd())
}
return rootCmd
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mitchellh/hashstructure v1.1.0
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/hashstructure v1.1.0 h1:P6P1hdjqAAknpY/M1CGipelZgp+4y9ja9kmUZPXP+H0=
github.com/mitchellh/hashstructure v1.1.0/go.mod h1:xUDAozZz0Wmdiufv0uyhnHkUTN6/6d8ulp4AwfLKrmA=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand Down
51 changes: 51 additions & 0 deletions kong2tf/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package kong2tf

import (
"github.com/kong/go-database-reconciler/pkg/file"
)

type ITerraformBuilder interface {
buildControlPlaneVar(*string)
buildServices(*file.Content, *string)
buildRoutes(*file.Content, *string)
buildGlobalPlugins(*file.Content, *string)
buildConsumers(*file.Content, *string, bool)
buildConsumerGroups(*file.Content, *string)
buildUpstreams(*file.Content, *string)
buildCACertificates(*file.Content, *string)
buildCertificates(*file.Content, *string)
buildVaults(*file.Content, *string)
getContent() string
}

func getTerraformBuilder() ITerraformBuilder {
return newDefaultTerraformBuilder()
}

type Director struct {
builder ITerraformBuilder
}

func newDirector(builder ITerraformBuilder) *Director {
return &Director{
builder: builder,
}
}

func (d *Director) builTerraformResources(
content *file.Content,
generateImportsForControlPlaneID *string,
ignoreCredentialChanges bool,
) string {
d.builder.buildControlPlaneVar(generateImportsForControlPlaneID)
d.builder.buildGlobalPlugins(content, generateImportsForControlPlaneID)
d.builder.buildServices(content, generateImportsForControlPlaneID)
d.builder.buildUpstreams(content, generateImportsForControlPlaneID)
d.builder.buildRoutes(content, generateImportsForControlPlaneID)
d.builder.buildConsumers(content, generateImportsForControlPlaneID, ignoreCredentialChanges)
d.builder.buildConsumerGroups(content, generateImportsForControlPlaneID)
d.builder.buildCACertificates(content, generateImportsForControlPlaneID)
d.builder.buildCertificates(content, generateImportsForControlPlaneID)
d.builder.buildVaults(content, generateImportsForControlPlaneID)
return d.builder.getContent()
}
Loading
Loading