avoid double unmarshalling

This commit is contained in:
Yann Hamon 2020-12-15 18:35:33 +01:00
parent 4afe9b1977
commit 29a8f4c09e
7 changed files with 72 additions and 17 deletions

View file

@ -5,6 +5,7 @@ import (
"fmt"
"log"
"os"
"runtime"
"runtime/pprof"
"sync"
@ -62,6 +63,8 @@ func realMain() int {
if err := pprof.StartCPUProfile(f); err != nil {
log.Fatal("could not start CPU profile: ", err)
}
runtime.SetBlockProfileRate(1)
defer pprof.StopCPUProfile()
}

View file

@ -75,7 +75,7 @@ func FromFlags(progName string, args []string) (Config, string, error) {
flags.StringVar(&c.OutputFormat, "output", "text", "output format - json, tap, text")
flags.BoolVar(&c.Verbose, "verbose", false, "print results for all resources")
flags.BoolVar(&c.SkipTLS, "insecure-skip-tls-verify", false, "disable verification of the server's SSL certificate. This will make your HTTPS connections insecure")
//flags.StringVar(&c.CPUProfileFile, "cpu-prof", "", "debug - log CPU profiling to file")
flags.StringVar(&c.CPUProfileFile, "cpu-prof", "", "debug - log CPU profiling to file")
flags.BoolVar(&c.Help, "h", false, "show help information")
flags.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: %s [OPTION]... [FILE OR FOLDER]...\n", progName)

View file

@ -111,8 +111,8 @@ func FromFiles(ctx context.Context, ignoreFilePatterns []string, paths ...string
}
}
close(resources)
close(errors)
close(resources)
}()
return resources, errors

View file

@ -42,3 +42,26 @@ func (res *Resource) Signature() (*Signature, error) {
res.sig = &Signature{Kind: resource.Kind, Version: resource.APIVersion, Namespace: resource.Metadata.Namespace, Name: name}
return res.sig, err
}
func (res *Resource) SignatureFromMap(m map[string]interface{}) (*Signature, error) {
if res.sig != nil {
return res.sig, nil
}
APIVersion, _ := m["apiVersion"].(string)
Kind, _ := m["kind"].(string)
var name, ns string
Metadata, ok := m["metadata"].(map[string]interface{})
if ok {
name, _ = Metadata["name"].(string)
ns, _ = Metadata["namespace"].(string)
if _, ok := Metadata["generateName"].(string); ok {
name = Metadata["generateName"].(string) + "{{ generateName }}"
}
}
// We cache the result to not unmarshall every time we want to access the signature
res.sig = &Signature{Kind: Kind, Version: APIVersion, Namespace: ns, Name: name}
return res.sig, nil
}

View file

@ -1,9 +1,12 @@
package resource_test
import (
"fmt"
"log"
"testing"
"github.com/yannh/kubeconform/pkg/resource"
"sigs.k8s.io/yaml"
)
func TestSignatureFromBytes(t *testing.T) {
@ -47,3 +50,29 @@ spec:
}
}
}
func TestSignatureFromMap(t *testing.T) {
testCases := []struct {
b string
}{
{
"apiVersion: v1\nkind: ReplicationController\nmetadata:\n name: \"bob\"\nspec:\n replicas: 2\n",
},
}
for _, testCase := range testCases {
res := resource.Resource{
Path: "foo",
Bytes: []byte(testCase.b),
}
var r map[string]interface{}
if err := yaml.Unmarshal(res.Bytes, &r); err != nil {
log.Fatal(err)
}
res.SignatureFromMap(r)
sig, _ := res.Signature()
fmt.Printf("%+v", sig)
}
}

View file

@ -109,7 +109,12 @@ func (val *v) ValidateResource(res resource.Resource) Result {
return Result{Resource: res, Err: nil, Status: Empty}
}
sig, err := res.Signature()
var r map[string]interface{}
if err := yaml.Unmarshal(res.Bytes, &r); err != nil {
return Result{Resource: res, Status: Error, Err: fmt.Errorf("error unmarshalling resource: %s", err)}
}
sig, err := res.SignatureFromMap(r)
if err != nil {
return Result{Resource: res, Err: fmt.Errorf("error while parsing: %s", err), Status: Error}
}
@ -122,11 +127,6 @@ func (val *v) ValidateResource(res resource.Resource) Result {
return Result{Resource: res, Err: fmt.Errorf("prohibited resource kind %s", sig.Kind), Status: Error}
}
var r map[string]interface{}
if err := yaml.Unmarshal(res.Bytes, &r); err != nil {
return Result{Resource: res, Status: Error, Err: fmt.Errorf("error unmarshalling resource: %s", err)}
}
if r == nil { // Resource is empty
return Result{Resource: res, Err: nil, Status: Empty}
}

View file

@ -18,7 +18,7 @@ func TestValidate(t *testing.T) {
{
"valid resource",
[]byte(`
Kind: name
kind: name
firstName: foo
lastName: bar
`),
@ -26,7 +26,7 @@ lastName: bar
"title": "Example Schema",
"type": "object",
"properties": {
"Kind": {
"kind": {
"type": "string"
},
"firstName": {
@ -48,7 +48,7 @@ lastName: bar
{
"invalid resource",
[]byte(`
Kind: name
kind: name
firstName: foo
lastName: bar
`),
@ -56,7 +56,7 @@ lastName: bar
"title": "Example Schema",
"type": "object",
"properties": {
"Kind": {
"kind": {
"type": "string"
},
"firstName": {
@ -78,14 +78,14 @@ lastName: bar
{
"missing required field",
[]byte(`
Kind: name
kind: name
firstName: foo
`),
[]byte(`{
"title": "Example Schema",
"type": "object",
"properties": {
"Kind": {
"kind": {
"type": "string"
},
"firstName": {
@ -107,7 +107,7 @@ firstName: foo
{
"resource has invalid yaml",
[]byte(`
Kind: name
kind: name
firstName foo
lastName: bar
`),
@ -115,7 +115,7 @@ lastName: bar
"title": "Example Schema",
"type": "object",
"properties": {
"Kind": {
"kind": {
"type": "string"
},
"firstName": {
@ -151,7 +151,7 @@ lastName: bar
regs: nil,
}
if got := val.ValidateResource(resource.Resource{Bytes: testCase.rawResource}); got.Status != testCase.expect {
t.Errorf("%d - expected %d, got %d", i, testCase.expect, got.Status)
t.Errorf("%d - expected %d, got %d: %s", i, testCase.expect, got.Status, got.Err.Error())
}
}
}