mirror of
https://github.com/yannh/kubeconform.git
synced 2026-04-28 14:24:37 +00:00
Migrate to santhosh-tekuri/jsonschema (#168)
* Migrate to santhosh-tekuri/jsonschema
This commit is contained in:
parent
84afe70659
commit
ee7c498580
65 changed files with 4651 additions and 9106 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue