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

feat(apiops): integrate go-apiops #939

Merged
merged 2 commits into from
Jul 14, 2023
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
41 changes: 41 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Table of Contents

- [v1.24.0](#v1240)
- [v1.23.0](#v1230)
- [v1.22.1](#v1221)
- [v1.22.0](#v1220)
Expand Down Expand Up @@ -60,6 +61,45 @@
- [v0.2.0](#v020)
- [v0.1.0](#v010)

## [v1.24.0]

> Release date: to-be-set

### Added

- Added a new command `file openapi2kong` that will generate a deck file from an OpenAPI
3.0 spec. This is the replacement for the similar `inso` functionality.
The functionality is imported from the [go-apiops library](https://github.com/Kong/go-apiops).
[#939](https://github.com/Kong/deck/pull/939)
- Added a new command `file merge` that will merge multiple deck files. The files will not be
validated, which allows for working with incomplete or even invalid files in a pipeline.
The functionality is imported from the [go-apiops library](https://github.com/Kong/go-apiops).
[#939](https://github.com/Kong/deck/pull/939)
- Added a new command `file patch` for applying patches on top of a decK file. The patches can be
provided on the commandline, or via patch files. The deck file will not be
validated, which allows for working with incomplete or even invalid files in a pipeline.
The functionality is imported from the [go-apiops library](https://github.com/Kong/go-apiops).
[#939](https://github.com/Kong/deck/pull/939)
- Added a new commands `file add-tags/list-tags/remove-tags` to manage tags in a decK file. The deck file will not be
validated, which allows for working with incomplete or even invalid files in a pipeline.
The functionality is imported from the [go-apiops library](https://github.com/Kong/go-apiops).
[#939](https://github.com/Kong/deck/pull/939)
- Added a new command `file add-plugins` for adding plugins to a decK file. The plugins can be
provided on the commandline, or via config files. The deck file will not be
validated, which allows for working with incomplete or even invalid files in a pipeline.
The functionality is imported from the [go-apiops library](https://github.com/Kong/go-apiops).
[#939](https://github.com/Kong/deck/pull/939)

### Fixes


### Misc

- Moved the `convert` command under the `file` sub-command, to be used as `deck file convert ...`. The
top level command `deck convert ...` is marked as deprecated and will be removed in a future version.
[#939](https://github.com/Kong/deck/pull/939)


## [v1.23.0]

> Release date: 2023/07/03
Expand Down Expand Up @@ -1264,6 +1304,7 @@ No breaking changes have been introduced in this release.

Debut release of decK

[v1.24.0]: https://github.com/kong/deck/compare/v1.23.0...v1.24.0
[v1.23.0]: https://github.com/kong/deck/compare/v1.22.1...v1.23.0
[v1.22.1]: https://github.com/kong/deck/compare/v1.22.0...v1.22.1
[v1.22.0]: https://github.com/kong/deck/compare/v1.21.0...v1.22.0
Expand Down
109 changes: 61 additions & 48 deletions cmd/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"fmt"
"log"
"os"

"github.com/kong/deck/convert"
Expand All @@ -18,61 +19,73 @@ var (
convertCmdAssumeYes bool
)

func executeConvert(_ *cobra.Command, _ []string) error {
sourceFormat, err := convert.ParseFormat(convertCmdSourceFormat)
if err != nil {
return err
}
destinationFormat, err := convert.ParseFormat(convertCmdDestinationFormat)
if err != nil {
return err
}

if convertCmdInputFile != "" {
if yes, err := utils.ConfirmFileOverwrite(
convertCmdOutputFile, "", convertCmdAssumeYes,
); err != nil {
return err
} else if !yes {
return nil
}

err = convert.Convert(convertCmdInputFile, convertCmdOutputFile, sourceFormat, destinationFormat)
if err != nil {
return fmt.Errorf("converting file: %w", err)
}
} else if is2xTo3xConversion() {
path, err := os.Getwd()
if err != nil {
return fmt.Errorf("getting current working directory: %w", err)
}
files, err := utils.ConfigFilesInDir(path)
if err != nil {
return fmt.Errorf("getting files from directory: %w", err)
}
for _, filename := range files {
err = convert.Convert(filename, filename, sourceFormat, destinationFormat)
if err != nil {
return fmt.Errorf("converting '%s' file: %w", filename, err)
}
}
}
if convertCmdDestinationFormat == "konnect" {
cprint.UpdatePrintf("Warning: konnect format type was deprecated in v1.12 and it will be removed\n" +
"in a future version. Please use your Kong configuration files with deck <cmd>.\n" +
"Please see https://docs.konghq.com/konnect/getting-started/import/.\n")
}
return nil
}

// newConvertCmd represents the convert command
func newConvertCmd() *cobra.Command {
func newConvertCmd(deprecated bool) *cobra.Command {
short := "Convert files from one format into another format"
execute := executeConvert
if deprecated {
short = "[deprecated] use 'file convert' instead"
execute = func(cmd *cobra.Command, args []string) error {
log.Println("Warning: the 'deck convert' command was deprecated and moved to 'deck file convert'")
return executeConvert(cmd, args)
}
}

convertCmd := &cobra.Command{
Use: "convert",
Short: "Convert files from one format into another format",
Short: short,
Long: `The convert command changes configuration files from one format
into another compatible format. For example, a configuration for 'kong-gateway-2.x'
can be converted into a 'kong-gateway-3.x' 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 convertCmdInputFile != "" {
if yes, err := utils.ConfirmFileOverwrite(
convertCmdOutputFile, "", convertCmdAssumeYes,
); err != nil {
return err
} else if !yes {
return nil
}

err = convert.Convert(convertCmdInputFile, convertCmdOutputFile, sourceFormat, destinationFormat)
if err != nil {
return fmt.Errorf("converting file: %w", err)
}
} else if is2xTo3xConversion() {
path, err := os.Getwd()
if err != nil {
return fmt.Errorf("getting current working directory: %w", err)
}
files, err := utils.ConfigFilesInDir(path)
if err != nil {
return fmt.Errorf("getting files from directory: %w", err)
}
for _, filename := range files {
err = convert.Convert(filename, filename, sourceFormat, destinationFormat)
if err != nil {
return fmt.Errorf("converting '%s' file: %w", filename, err)
}
}
}
if convertCmdDestinationFormat == "konnect" {
cprint.UpdatePrintf("Warning: konnect format type was deprecated in v1.12 and it will be removed\n" +
"in a future version. Please use your Kong configuration files with deck <cmd>.\n" +
"Please see https://docs.konghq.com/konnect/getting-started/import/.\n")
}
return nil
},
RunE: execute,
}

sourceFormats := []convert.Format{convert.FormatKongGateway, convert.FormatKongGateway2x}
Expand Down
24 changes: 24 additions & 0 deletions cmd/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
*/
package cmd

import (
"github.com/spf13/cobra"
)

//
//
// Define the CLI data for the file sub-command
//
//

func newAddFileCmd() *cobra.Command {
addFileCmd := &cobra.Command{
Use: "file [sub-command]...",
Short: "Sub-command to host the decK file manipulation operations",
Long: `Sub-command to host the decK file manipulation operations`,
}

return addFileCmd
}
158 changes: 158 additions & 0 deletions cmd/file_addplugins.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
*/
package cmd

import (
"fmt"
"log"
"strings"

"github.com/kong/go-apiops/deckformat"
"github.com/kong/go-apiops/filebasics"
"github.com/kong/go-apiops/jsonbasics"
"github.com/kong/go-apiops/logbasics"
"github.com/kong/go-apiops/plugins"
"github.com/spf13/cobra"
)

var (
cmdAddPluginsOverwrite bool
cmdAddPluginsInputFilename string
cmdAddPluginOutputFilename string
cmdAddPluginOutputFormat string
cmdAddPluginsSelectors []string
cmdAddPluginsStrConfigs []string
)

// Executes the CLI command "add-plugins"
func executeAddPlugins(cmd *cobra.Command, cfgFiles []string) error {
verbosity, _ := cmd.Flags().GetInt("verbose")
logbasics.Initialize(log.LstdFlags, verbosity)

cmdAddPluginOutputFormat = strings.ToUpper(cmdAddPluginOutputFormat)

var pluginConfigs []map[string]interface{}
{
for _, strConfig := range cmdAddPluginsStrConfigs {
pluginConfig, err := filebasics.Deserialize([]byte(strConfig))
if err != nil {
return fmt.Errorf("failed to deserialize plugin config '%s'; %w", strConfig, err)
}
pluginConfigs = append(pluginConfigs, pluginConfig)
}
}

var pluginFiles []plugins.DeckPluginFile
{
for _, filename := range cfgFiles {
var file plugins.DeckPluginFile
if err := file.ParseFile(filename); err != nil {
return fmt.Errorf("failed to parse plugin file '%s'; %w", filename, err)
}
pluginFiles = append(pluginFiles, file)
}
}

// do the work: read/add-plugins/write
jsondata, err := filebasics.DeserializeFile(cmdAddPluginsInputFilename)
if err != nil {
return fmt.Errorf("failed to read input file '%s'; %w", cmdAddPluginsInputFilename, err)
}
yamlNode := jsonbasics.ConvertToYamlNode(jsondata)

// apply CLI flags
plugger := plugins.Plugger{}
plugger.SetYamlData(yamlNode)
err = plugger.SetSelectors(cmdAddPluginsSelectors)
if err != nil {
return fmt.Errorf("failed to set selectors; %w", err)
}
err = plugger.AddPlugins(pluginConfigs, cmdAddPluginsOverwrite)
if err != nil {
return fmt.Errorf("failed to add plugins; %w", err)
}
yamlNode = plugger.GetYamlData()

// apply plugin-files
for i, pluginFile := range pluginFiles {
err = pluginFile.Apply(yamlNode)
if err != nil {
return fmt.Errorf("failed to apply plugin file '%s'; %w", cfgFiles[i], err)
}
}
jsondata = plugger.GetData()

trackInfo := deckformat.HistoryNewEntry("add-plugins")
trackInfo["input"] = cmdAddPluginsInputFilename
trackInfo["output"] = cmdAddPluginOutputFilename
trackInfo["overwrite"] = cmdAddPluginsOverwrite
if len(pluginConfigs) > 0 {
trackInfo["configs"] = pluginConfigs
}
if len(cfgFiles) > 0 {
trackInfo["pluginfiles"] = cfgFiles
}
trackInfo["selectors"] = cmdAddPluginsSelectors
deckformat.HistoryAppend(jsondata, trackInfo)

return filebasics.WriteSerializedFile(cmdAddPluginOutputFilename, jsondata, cmdAddPluginOutputFormat)
}

//
//
// Define the CLI data for the add-plugins command
//
//

func newAddPluginsCmd() *cobra.Command {
addPluginsCmd := &cobra.Command{
Use: "add-plugins [flags] [...plugin-files]",
Short: "Add plugins to objects in a decK file",
Long: `Add plugins to objects in a decK file.

The plugins are added to all objects that match the selector expressions. If no
selectors are given, they will be added to the top-level 'plugins' array.

The plugin-files have the following format (JSON or YAML) and are applied in the
order they are given;

{ "_format_version": "1.0",
"add-plugins": [
{ "selectors": [
"$..services[*]"
],
"overwrite": false,
"plugins": [
{ "name": "my-plugin",
"config": {
"my-property": "value"
}
}
],
}
]
}
`,
RunE: executeAddPlugins,
Args: cobra.MinimumNArgs(0),
}

addPluginsCmd.Flags().StringVarP(&cmdAddPluginsInputFilename, "state", "s", "-",
"decK file to process. Use - to read from stdin")
addPluginsCmd.Flags().StringArrayVar(&cmdAddPluginsSelectors, "selector", []string{},
"JSON path expression to select plugin-owning objects to add plugins to,\n"+
"defaults to the top-level (selector '$'). Repeat for multiple selectors.")
addPluginsCmd.Flags().StringArrayVar(&cmdAddPluginsStrConfigs, "config", []string{},
"JSON snippet containing the plugin configuration to add. Repeat to add\n"+
"multiple plugins.")
addPluginsCmd.Flags().BoolVar(&cmdAddPluginsOverwrite, "overwrite", false,
"specifying this flag will overwrite plugins by the same name if they already\n"+
"exist in an array. The default is to skip existing plugins.")
addPluginsCmd.Flags().StringVarP(&cmdAddPluginOutputFilename, "output-file", "o", "-",
"output file to write. Use - to write to stdout")
addPluginsCmd.Flags().StringVarP(&cmdAddPluginOutputFormat, "format", "", filebasics.OutputFormatYaml,
"output format: "+filebasics.OutputFormatJSON+" or "+filebasics.OutputFormatYaml)

return addPluginsCmd
}
Loading
Loading