Migrate to santhosh-tekuri/jsonschema (#168)

* Migrate to santhosh-tekuri/jsonschema
This commit is contained in:
Yann Hamon 2023-01-23 19:22:20 +01:00 committed by GitHub
parent 84afe70659
commit ee7c498580
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
65 changed files with 4651 additions and 9106 deletions

View file

@ -61,15 +61,15 @@ func newHTTPRegistry(schemaPathTemplate string, cacheFolder string, strict bool,
}
// DownloadSchema downloads the schema for a particular resource from an HTTP server
func (r SchemaRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) ([]byte, error) {
func (r SchemaRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) (string, []byte, error) {
url, err := schemaPath(r.schemaPathTemplate, resourceKind, resourceAPIVersion, k8sVersion, r.strict)
if err != nil {
return nil, err
return "", nil, err
}
if r.cache != nil {
if b, err := r.cache.Get(resourceKind, resourceAPIVersion, k8sVersion); err == nil {
return b.([]byte), nil
return url, b.([]byte), nil
}
}
@ -79,7 +79,7 @@ func (r SchemaRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVers
if r.debug {
log.Println(msg)
}
return nil, errors.New(msg)
return url, nil, errors.New(msg)
}
defer resp.Body.Close()
@ -88,7 +88,7 @@ func (r SchemaRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVers
if r.debug {
log.Print(msg)
}
return nil, newNotFoundError(errors.New(msg))
return url, nil, newNotFoundError(errors.New(msg))
}
if resp.StatusCode != http.StatusOK {
@ -96,7 +96,7 @@ func (r SchemaRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVers
if r.debug {
log.Print(msg)
}
return nil, fmt.Errorf(msg)
return url, nil, fmt.Errorf(msg)
}
body, err := ioutil.ReadAll(resp.Body)
@ -105,7 +105,7 @@ func (r SchemaRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVers
if r.debug {
log.Print(msg)
}
return nil, errors.New(msg)
return url, nil, errors.New(msg)
}
if r.debug {
@ -114,9 +114,9 @@ func (r SchemaRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVers
if r.cache != nil {
if err := r.cache.Set(resourceKind, resourceAPIVersion, k8sVersion, body); err != nil {
return nil, fmt.Errorf("failed writing schema to cache: %s", err)
return url, nil, fmt.Errorf("failed writing schema to cache: %s", err)
}
}
return body, nil
return url, body, nil
}

View file

@ -100,7 +100,7 @@ func TestDownloadSchema(t *testing.T) {
strict: testCase.strict,
}
res, err := reg.DownloadSchema(testCase.resourceKind, testCase.resourceAPIVersion, testCase.k8sversion)
_, res, err := reg.DownloadSchema(testCase.resourceKind, testCase.resourceAPIVersion, testCase.k8sversion)
if err == nil || testCase.expectErr == nil {
if err != testCase.expectErr {
t.Errorf("during test '%s': expected error, got:\n%s\n%s\n", testCase.name, testCase.expectErr, err)

View file

@ -24,10 +24,10 @@ func newLocalRegistry(pathTemplate string, strict bool, debug bool) (*LocalRegis
}
// DownloadSchema retrieves the schema from a file for the resource
func (r LocalRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) ([]byte, error) {
func (r LocalRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) (string, []byte, error) {
schemaFile, err := schemaPath(r.pathTemplate, resourceKind, resourceAPIVersion, k8sVersion, r.strict)
if err != nil {
return []byte{}, nil
return schemaFile, []byte{}, nil
}
f, err := os.Open(schemaFile)
if err != nil {
@ -36,14 +36,14 @@ func (r LocalRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersi
if r.debug {
log.Print(msg)
}
return nil, newNotFoundError(errors.New(msg))
return schemaFile, nil, newNotFoundError(errors.New(msg))
}
msg := fmt.Sprintf("failed to open schema at %s: %s", schemaFile, err)
if r.debug {
log.Print(msg)
}
return nil, errors.New(msg)
return schemaFile, nil, errors.New(msg)
}
defer f.Close()
@ -53,11 +53,11 @@ func (r LocalRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersi
if r.debug {
log.Print(msg)
}
return nil, err
return schemaFile, nil, err
}
if r.debug {
log.Printf("using schema found at %s", schemaFile)
}
return content, nil
return schemaFile, content, nil
}

View file

@ -13,7 +13,7 @@ type Manifest struct {
// Registry is an interface that should be implemented by any source of Kubernetes schemas
type Registry interface {
DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) ([]byte, error)
DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) (string, []byte, error)
}
// Retryable indicates whether an error is a temporary or a permanent failure

View file

@ -6,11 +6,11 @@ import (
"fmt"
"io"
jsonschema "github.com/santhosh-tekuri/jsonschema/v5"
_ "github.com/santhosh-tekuri/jsonschema/v5/httploader"
"github.com/yannh/kubeconform/pkg/cache"
"github.com/yannh/kubeconform/pkg/registry"
"github.com/yannh/kubeconform/pkg/resource"
"github.com/xeipuuv/gojsonschema"
"sigs.k8s.io/yaml"
)
@ -91,7 +91,7 @@ func New(schemaLocations []string, opts Opts) (Validator, error) {
type v struct {
opts Opts
schemaCache cache.Cache
schemaDownload func(registries []registry.Registry, kind, version, k8sVersion string) (*gojsonschema.Schema, error)
schemaDownload func(registries []registry.Registry, kind, version, k8sVersion string) (*jsonschema.Schema, error)
regs []registry.Registry
}
@ -151,13 +151,13 @@ func (val *v) ValidateResource(res resource.Resource) Result {
}
cached := false
var schema *gojsonschema.Schema
var schema *jsonschema.Schema
if val.schemaCache != nil {
s, err := val.schemaCache.Get(sig.Kind, sig.Version, val.opts.KubernetesVersion)
if err == nil {
cached = true
schema = s.(*gojsonschema.Schema)
schema = s.(*jsonschema.Schema)
}
}
@ -179,28 +179,12 @@ func (val *v) ValidateResource(res resource.Resource) Result {
return Result{Resource: res, Err: fmt.Errorf("could not find schema for %s", sig.Kind), Status: Error}
}
resourceLoader := gojsonschema.NewGoLoader(r)
results, err := schema.Validate(resourceLoader)
err = schema.Validate(r)
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 Result{Resource: res, Status: Error, Err: fmt.Errorf("problem validating schema. Check JSON formatting: %s", err)}
return Result{Resource: res, Status: Invalid, Err: fmt.Errorf("problem validating schema. Check JSON formatting: %s", err)}
}
if results.Valid() {
return Result{Resource: res, Status: Valid}
}
msg := ""
for _, errMsg := range results.Errors() {
if msg != "" {
msg += " - "
}
details := errMsg.Details()
msg += fmt.Sprintf("For field %s: %s", details["field"].(string), errMsg.Description())
}
return Result{Resource: res, Status: Invalid, Err: fmt.Errorf("%s", msg)}
return Result{Resource: res, Status: Valid}
}
// ValidateWithContext validates resources found in r
@ -235,15 +219,15 @@ func (val *v) Validate(filename string, r io.ReadCloser) []Result {
return val.ValidateWithContext(context.Background(), filename, r)
}
func downloadSchema(registries []registry.Registry, kind, version, k8sVersion string) (*gojsonschema.Schema, error) {
func downloadSchema(registries []registry.Registry, kind, version, k8sVersion string) (*jsonschema.Schema, error) {
var err error
var schemaBytes []byte
var path string
for _, reg := range registries {
schemaBytes, err = reg.DownloadSchema(kind, version, k8sVersion)
path, schemaBytes, err = reg.DownloadSchema(kind, version, k8sVersion)
if err == nil {
schema, err := gojsonschema.NewSchema(gojsonschema.NewBytesLoader(schemaBytes))
schema, err := jsonschema.CompileString(path, string(schemaBytes))
// If we got a non-parseable response, we try the next registry
if err != nil {
continue

View file

@ -9,16 +9,16 @@ import (
)
type mockRegistry struct {
SchemaDownloader func() ([]byte, error)
SchemaDownloader func() (string, []byte, error)
}
func newMockRegistry(f func() ([]byte, error)) *mockRegistry {
func newMockRegistry(f func() (string, []byte, error)) *mockRegistry {
return &mockRegistry{
SchemaDownloader: f,
}
}
func (m mockRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) ([]byte, error) {
func (m mockRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) (string, []byte, error) {
return m.SchemaDownloader()
}
@ -362,17 +362,17 @@ lastName: bar
schemaCache: nil,
schemaDownload: downloadSchema,
regs: []registry.Registry{
newMockRegistry(func() ([]byte, error) {
return testCase.schemaRegistry1, nil
newMockRegistry(func() (string, []byte, error) {
return "", testCase.schemaRegistry1, nil
}),
newMockRegistry(func() ([]byte, error) {
return testCase.schemaRegistry2, nil
newMockRegistry(func() (string, []byte, error) {
return "", testCase.schemaRegistry2, nil
}),
},
}
if got := val.ValidateResource(resource.Resource{Bytes: testCase.rawResource}); got.Status != testCase.expect {
if got.Err != nil {
t.Errorf("%d - expected %d, got %d: %s", i, testCase.expect, got.Status, got.Err.Error())
t.Errorf("Test '%s' - expected %d, got %d: %s", testCase.name, testCase.expect, got.Status, got.Err.Error())
} else {
t.Errorf("%d - expected %d, got %d", i, testCase.expect, got.Status)
}