Skip to content

Commit

Permalink
Merge pull request #87 from OpsLevel/kr/bubble-up-jq-errors-flag
Browse files Browse the repository at this point in the history
bugfix: bubble up JQ errors are warning logs to help diagnose problems
  • Loading branch information
rocktavious authored Sep 29, 2021
2 parents 93f13e8 + 29531af commit 50cce85
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 48 deletions.
31 changes: 12 additions & 19 deletions src/common/jqparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package common
import (
"encoding/json"
"fmt"
"strings"

"github.com/opslevel/kubectl-opslevel/jq"

_ "github.com/rs/zerolog/log"
"github.com/rs/zerolog/log"
)

type JQParser struct {
Expand Down Expand Up @@ -48,47 +49,39 @@ func NewJQParser(filter string) JQParser {
}

func NewJQParserMulti(filter string) JQParser {
parser := JQParser{JQ: jq.New(fmt.Sprintf("map(%s // null)", filter))}
parser := JQParser{JQ: jq.New(fmt.Sprintf("map((%s) // null)", filter))}
return parser
}

func (parser *JQParser) doParse(data []byte) []byte {
func (parser *JQParser) doParse(field string, data []byte) []byte {
var bytes []byte
var err *jq.JQError
bytes, err = parser.JQ.Run(data)
if err != nil {
//fmt.Println(err.Error())
switch err.Type {
case jq.BadOptions:
return nil
case jq.BadFilter:
return []byte(fmt.Sprintf("\"%s\"", parser.JQ.Filter()))
case jq.BadJSON:
return nil
case jq.BadExcution:
return nil
}
filter := strings.TrimSuffix(strings.TrimPrefix(parser.JQ.Filter(), "map(("), ") // null)")
log.Warn().Str("Field", field).Str("Filter", filter).Msgf(strings.ReplaceAll(err.Error(), parser.JQ.Filter(), ""))
return nil
}
return bytes
}

func (parser *JQParser) Parse(data []byte) *JQResponse {
func (parser *JQParser) Parse(field string, data []byte) *JQResponse {
var resp *JQResponse
if parser.JQ.Filter() == "" {
resp = &JQResponse{Bytes: []byte("")}
} else {
resp = &JQResponse{Bytes: parser.doParse(data)}
resp = &JQResponse{Bytes: parser.doParse(field, data)}
}
resp.Unmarshal()
return resp
}

func (parser *JQParser) ParseMulti(data []byte) *JQResponseMulti {
func (parser *JQParser) ParseMulti(field string, data []byte) *JQResponseMulti {
var resp *JQResponseMulti
if parser.JQ.Filter() == "map( // null)" {
if parser.JQ.Filter() == "map(() // null)" {
resp = &JQResponseMulti{Bytes: []byte("[]")}
} else {
resp = &JQResponseMulti{Bytes: parser.doParse(data)}
resp = &JQResponseMulti{Bytes: parser.doParse(field, data)}
}
resp.Unmarshal()
return resp
Expand Down
47 changes: 24 additions & 23 deletions src/common/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package common

import (
"encoding/json"
"fmt"

"github.com/opslevel/kubectl-opslevel/config"
"github.com/opslevel/kubectl-opslevel/jq"
Expand Down Expand Up @@ -31,15 +32,15 @@ type ServiceRegistration struct {
Repositories []opslevel.ServiceRepositoryCreateInput `json:",omitempty"` // This is a concrete class so fields are validated during `service preview`
}

func parseField(filter string, resources []byte) *JQResponseMulti {
func parseField(field string, filter string, resources []byte) *JQResponseMulti {
parser := NewJQParserMulti(filter)
return parser.ParseMulti(resources)
return parser.ParseMulti(field, resources)
}

func parseFieldArray(filters []string, resources []byte) []*JQResponseMulti {
func parseFieldArray(field string, filters []string, resources []byte) []*JQResponseMulti {
var output []*JQResponseMulti
for _, filter := range filters {
output = append(output, parseField(filter, resources))
for i, filter := range filters {
output = append(output, parseField(fmt.Sprintf("%s[%d]", field, i+1), filter, resources))
}
return output
}
Expand Down Expand Up @@ -171,26 +172,26 @@ func GetString(index int, data *JQResponseMulti) string {
}

// TODO: bubble up errors
func Parse(c config.ServiceRegistrationConfig, count int, resources []byte) ([]ServiceRegistration, error) {
func Parse(field string, c config.ServiceRegistrationConfig, count int, resources []byte) ([]ServiceRegistration, error) {
services := make([]ServiceRegistration, count)

// Parse
Names := parseField(c.Name, resources)
Descriptions := parseField(c.Description, resources)
Owners := parseField(c.Owner, resources)
Lifecycles := parseField(c.Lifecycle, resources)
Tiers := parseField(c.Tier, resources)
Products := parseField(c.Product, resources)
Languages := parseField(c.Language, resources)
Frameworks := parseField(c.Framework, resources)
Aliases := parseFieldArray(c.Aliases, resources)
if len(Aliases) < 1 {
Names := parseField(fmt.Sprintf("%s.name", field), c.Name, resources)
Descriptions := parseField(fmt.Sprintf("%s.description", field), c.Description, resources)
Owners := parseField(fmt.Sprintf("%s.owner", field), c.Owner, resources)
Lifecycles := parseField(fmt.Sprintf("%s.lifecycle", field), c.Lifecycle, resources)
Tiers := parseField(fmt.Sprintf("%s.tier", field), c.Tier, resources)
Products := parseField(fmt.Sprintf("%s.product", field), c.Product, resources)
Languages := parseField(fmt.Sprintf("%s.language", field), c.Language, resources)
Frameworks := parseField(fmt.Sprintf("%s.framework", field), c.Framework, resources)
Aliases := parseFieldArray(fmt.Sprintf("%s.aliases", field), c.Aliases, resources)
if len(Aliases) < 1 {
Aliases = append(Aliases, parseField("Auto Added Alias", "\"k8s:\\(.metadata.name)-\\(.metadata.namespace)\"", resources))
}
TagAssigns := parseFieldArray(c.Tags.Assign, resources)
TagCreates := parseFieldArray(c.Tags.Create, resources)
Tools := parseFieldArray(c.Tools, resources)
Repositories := parseFieldArray(c.Repositories, resources)
TagAssigns := parseFieldArray(fmt.Sprintf("%s.tags.assign", field), c.Tags.Assign, resources)
TagCreates := parseFieldArray(fmt.Sprintf("%s.tags.create", field), c.Tags.Create, resources)
Tools := parseFieldArray(fmt.Sprintf("%s.tools", field), c.Tools, resources)
Repositories := parseFieldArray(fmt.Sprintf("%s.repository", field), c.Repositories, resources)

// Aggregate
for i := 0; i < count; i++ {
Expand Down Expand Up @@ -284,7 +285,7 @@ func QueryForServices(c *config.Config) ([]ServiceRegistration, error) {

jq.ValidateInstalled()

for _, importConfig := range c.Service.Import {
for i, importConfig := range c.Service.Import {
selector := importConfig.SelectorConfig
if selectorErr := selector.Validate(); selectorErr != nil {
return services, selectorErr
Expand All @@ -296,7 +297,7 @@ func QueryForServices(c *config.Config) ([]ServiceRegistration, error) {
}

resources = filterResources(selector, resources)
parsedServices, parseError := Parse(importConfig.OpslevelConfig, len(resources), joinResources(resources))
parsedServices, parseError := Parse(fmt.Sprintf("service.import[%d]", i+1), importConfig.OpslevelConfig, len(resources), joinResources(resources))
if parseError != nil {
return services, parseError
}
Expand Down Expand Up @@ -334,7 +335,7 @@ func filterResources(selector k8sutils.KubernetesSelector, resources [][]byte) [
var output [][]byte
resourceCount := len(resources)
// Parse
filterResults := parseFieldArray(selector.Excludes, joinResources(resources))
filterResults := parseFieldArray("selector.excludes", selector.Excludes, joinResources(resources))

// Aggregate
for resourceIndex := 0; resourceIndex < resourceCount; resourceIndex++ {
Expand Down
12 changes: 6 additions & 6 deletions src/jq/jq.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,17 @@ func (e *JQError) Error() string {
case EmptyFilter:
return "Empty JQ Filter"
case BadOptions:
return fmt.Sprintf("Bad JQ Options: `%s`", e.Message)
return fmt.Sprintf("Invalid JQ Options %s", e.Message)
case BadFilter:
return fmt.Sprintf("Bad JQ Filter: `%s`", e.Message)
return fmt.Sprintf("Invalid JQ Filter %s", e.Message)
case BadJSON:
return fmt.Sprintf("Bad Json: `%s`", e.Message)
return fmt.Sprintf("Invalid Json %s", e.Message)
case BadExcution:
return fmt.Sprintf("Bad JQ Execution: `%s`", e.Message)
return fmt.Sprintf("Failed JQ Execution %s", strings.TrimSuffix(e.Message, "\n"))
case Unknown:
return fmt.Sprintf("Unknown JQ Error: `%s`", e.Message)
return fmt.Sprintf("Unknown JQ Error %s", e.Message)
}
panic(fmt.Sprintf("Unknown JQ Error Occured!"))
panic(fmt.Sprintf("Unknown JQ Error %s", e.Message))
}

func (jq *JQ) Filter() string {
Expand Down

0 comments on commit 50cce85

Please sign in to comment.