diff --git a/go.mod b/go.mod index 1f01f27..2676f7c 100644 --- a/go.mod +++ b/go.mod @@ -5,4 +5,5 @@ go 1.14 require ( github.com/xeipuuv/gojsonschema v1.2.0 gopkg.in/yaml.v2 v2.3.0 + sigs.k8s.io/yaml v1.2.0 ) diff --git a/go.sum b/go.sum index 529ab99..99f502b 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,5 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -9,5 +10,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/main.go b/main.go index e3000aa..1ff26f2 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,8 @@ package main import ( + "fmt" + "io" "io/ioutil" "log" "os" @@ -10,6 +12,35 @@ import ( "github.com/yannh/kubeconform/pkg/validator" ) +func validateFile(f io.Reader, regs []*registry.KubernetesRegistry, k8sVersion string) error { + rawResource, err := ioutil.ReadAll(f) + if err != nil { + return fmt.Errorf("failed reading file: %s", err) + } + + sig, err := resource.SignatureFromBytes(rawResource) + if err != nil { + return fmt.Errorf("error while parsing: %s", err) + } + + var schema []byte + for _, reg := range regs { + schema, err = reg.DownloadSchema(sig.Kind, sig.Version, k8sVersion) + if err == nil { + break + } + } + if err != nil { + return fmt.Errorf("failed downloading schema for resource") + } + + if err = validator.Validate(rawResource, schema); err != nil { + return err + } + + return nil +} + func realMain() int { const k8sVersion = "1.18.0" filename := "fixtures/valid_1.yaml" @@ -21,35 +52,17 @@ func realMain() int { } defer f.Close() - rawResource, err := ioutil.ReadAll(f) - if err != nil { - log.Printf("failed reading file %s", filename) - return 1 - } - - sig, err := resource.SignatureFromBytes(rawResource) - if err != nil { - log.Printf("failed parsing %s", filename) - return 1 - } - r := registry.NewKubernetesRegistry() - schema, err := r.DownloadSchema(sig.Kind, sig.Version, k8sVersion) - - if err != nil { - log.Printf("error downloading Schema: %s", err) + if err = validateFile(f, []*registry.KubernetesRegistry{r}, k8sVersion); err != nil { + if _, ok := err.(validator.InvalidResourceError); ok { + log.Printf("invalid resource: %s", err) + return 1 + } + log.Printf("failed validating resource: %s", err) return 1 } - err = validator.Validate(rawResource, schema) - if err != nil { - log.Printf("failed validating: %s", err) - return 1 - } - - - log.Printf("resource is valid!: %s", schema) - + log.Printf("resource is valid: %s", filename) return 0 } diff --git a/pkg/resource/main.go b/pkg/resource/main.go index bf55c30..37515b0 100644 --- a/pkg/resource/main.go +++ b/pkg/resource/main.go @@ -1,7 +1,7 @@ package resource import ( - yaml "gopkg.in/yaml.v2" + "sigs.k8s.io/yaml" ) type Signature struct { diff --git a/pkg/validator/main.go b/pkg/validator/main.go index 1f54bd1..6a604a4 100644 --- a/pkg/validator/main.go +++ b/pkg/validator/main.go @@ -3,8 +3,14 @@ package validator import ( "fmt" "github.com/xeipuuv/gojsonschema" + "sigs.k8s.io/yaml" ) +type InvalidResourceError struct { err string } +func (r InvalidResourceError) Error() string{ + return r.err +} + // ValidFormat is a type for quickly forcing // new formats on the gojsonschema loader type ValidFormat struct{} @@ -19,22 +25,27 @@ func init () { gojsonschema.FormatCheckers.Add("int-or-string", ValidFormat{}) } -func Validate(resource interface{}, rawSchema []byte) error { +func Validate(rawResource []byte, rawSchema []byte) error { schemaLoader := gojsonschema.NewBytesLoader(rawSchema) schema, err := gojsonschema.NewSchema(schemaLoader) if err != nil { return err } - documentLoader := gojsonschema.NewGoLoader(resource) - results, err := schema.Validate(documentLoader) + var resource map[string]interface{} + if err = yaml.Unmarshal(rawResource, &resource); err != nil { + return fmt.Errorf("error unmarshalling resource: %s", err) + } + resourceLoader := gojsonschema.NewGoLoader(resource) + + results, err := schema.Validate(resourceLoader) if err != nil { // This error can only happen if the Object to validate is poorly formed. There's no hope of saving this one return fmt.Errorf("problem validating schema. Check JSON formatting: %s", err) } if !results.Valid() { - return fmt.Errorf("resource does not conform to schema") + return InvalidResourceError{err: fmt.Sprintf("resource does not conform to schema: %+v", results) } } return nil