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: improve error logs when running sync/diff/validate #976

Merged
merged 2 commits into from
Jul 19, 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
8 changes: 5 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,12 @@

## [v1.24.0]

> Release date: to-be-set
> Release date: 2023/07/19

### Added

- Improved error logs coming from files validation against Kong's schemas.
[#976](https://github.com/Kong/deck/pull/976)
- 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).
Expand Down Expand Up @@ -95,8 +97,8 @@

### 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.
- 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)


Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ test-all: lint test

.PHONY: test
test:
go test -race ./...
go test -race -count=1 ./...

.PHONY: lint
lint:
Expand Down
46 changes: 25 additions & 21 deletions file/readfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,44 +20,48 @@ import (
// file, depending on the type of each item in filenames, merges the content of
// these files and renders a Content.
func getContent(filenames []string) (*Content, error) {
var allReaders []io.Reader
var workspaces []string
var res Content
var errs []error
for _, fileOrDir := range filenames {
readers, err := getReaders(fileOrDir)
if err != nil {
return nil, err
}
allReaders = append(allReaders, readers...)
}
var res Content
for _, r := range allReaders {
content, err := readContent(r)
if err != nil {
return nil, fmt.Errorf("reading file: %w", err)
}
if content.Workspace != "" {
workspaces = append(workspaces, content.Workspace)
}
err = mergo.Merge(&res, content, mergo.WithAppendSlice)
if err != nil {
return nil, fmt.Errorf("merging file contents: %w", err)

for filename, r := range readers {
content, err := readContent(r)
if err != nil {
errs = append(errs, fmt.Errorf("reading file %s: %w", filename, err))
continue
}
if content.Workspace != "" {
workspaces = append(workspaces, content.Workspace)
}
err = mergo.Merge(&res, content, mergo.WithAppendSlice)
if err != nil {
return nil, fmt.Errorf("merging file contents: %w", err)
}
}
}
if len(errs) > 0 {
return nil, utils.ErrArray{Errors: errs}
}
if err := validateWorkspaces(workspaces); err != nil {
return nil, err
}
return &res, nil
}

// getReaders returns back io.Readers representing all the YAML and JSON
// files in a directory. If fileOrDir is a single file, then it
// getReaders returns back a map of filename:io.Reader representing all the
// YAML and JSON files in a directory. If fileOrDir is a single file, then it
// returns back the reader for the file.
// If fileOrDir is equal to "-" string, then it returns back a io.Reader
// for the os.Stdin file descriptor.
func getReaders(fileOrDir string) ([]io.Reader, error) {
func getReaders(fileOrDir string) (map[string]io.Reader, error) {
// special case where `-` means stdin
if fileOrDir == "-" {
return []io.Reader{os.Stdin}, nil
return map[string]io.Reader{"STDIN": os.Stdin}, nil
}

finfo, err := os.Stat(fileOrDir)
Expand All @@ -75,13 +79,13 @@ func getReaders(fileOrDir string) ([]io.Reader, error) {
files = append(files, fileOrDir)
}

var res []io.Reader
res := make(map[string]io.Reader, len(files))
for _, file := range files {
f, err := os.Open(file)
if err != nil {
return nil, fmt.Errorf("opening file: %w", err)
}
res = append(res, bufio.NewReader(f))
res[file] = bufio.NewReader(f)
}
return res, nil
}
Expand Down
46 changes: 40 additions & 6 deletions file/readfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import (
"reflect"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/kong/deck/utils"
"github.com/kong/go-kong/kong"
"github.com/stretchr/testify/require"
)

func Test_configFilesInDir(t *testing.T) {
Expand Down Expand Up @@ -66,15 +67,17 @@ func Test_getReaders(t *testing.T) {
tests := []struct {
name string
args args
want []io.Reader
want map[string]io.Reader
// length of returned array
wantLen int
wantErr bool
}{
{
name: "read from standard input",
args: args{"-"},
want: []io.Reader{os.Stdin},
name: "read from standard input",
args: args{"-"},
want: map[string]io.Reader{
"STDIN": os.Stdin,
},
wantLen: 1,
wantErr: false,
},
Expand Down Expand Up @@ -126,6 +129,29 @@ func Test_getReaders(t *testing.T) {
}
}

func sortSlices(x, y interface{}) bool {
var xName, yName string
switch xEntity := x.(type) {
case FService:
yEntity := y.(FService)
xName = *xEntity.Name
yName = *yEntity.Name
case FRoute:
yEntity := y.(FRoute)
xName = *xEntity.Name
yName = *yEntity.Name
case FConsumer:
yEntity := y.(FConsumer)
xName = *xEntity.Username
yName = *yEntity.Username
case FPlugin:
yEntity := y.(FPlugin)
xName = *xEntity.Name
yName = *yEntity.Name
}
return xName < yName
}

func Test_getContent(t *testing.T) {
type args struct {
filenames []string
Expand Down Expand Up @@ -556,7 +582,15 @@ kong.log.set_serialize_value("span_id", parse_traceid(ngx.ctx.KONG_SPANS[1].span
t.Errorf("getContent() error = %v, wantErr %v", err, tt.wantErr)
return
}
require.Equal(t, tt.want, got)

opt := []cmp.Option{
cmpopts.SortSlices(sortSlices),
cmpopts.SortSlices(func(a, b *string) bool { return *a < *b }),
cmpopts.EquateEmpty(),
}
if diff := cmp.Diff(got, tt.want, opt...); diff != "" {
t.Errorf(diff)
}
})
}
}
Expand Down
19 changes: 17 additions & 2 deletions file/validate.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
package file

import (
"encoding/json"
"errors"
"fmt"

"github.com/kong/deck/utils"
"github.com/xeipuuv/gojsonschema"
"sigs.k8s.io/yaml"
)

type ValidationError struct {
Object string `json:"object"`
Err error `json:"error"`
}

func (e *ValidationError) Error() string {
return fmt.Sprintf("validation error: object=%s, err=%v", e.Object, e.Err)
}

func validate(content []byte) error {
var c map[string]interface{}
err := yaml.Unmarshal(content, &c)
Expand All @@ -24,10 +35,14 @@ func validate(content []byte) error {
if result.Valid() {
return nil
}

var errs utils.ErrArray
for _, desc := range result.Errors() {
err := fmt.Errorf(desc.String())
errs.Errors = append(errs.Errors, err)
jsonString, err := json.Marshal(desc.Value())
if err != nil {
return err
}
errs.Errors = append(errs.Errors, &ValidationError{Object: string(jsonString), Err: errors.New(desc.String())})
}
return errs
}
Expand Down
Loading