mirror of
https://github.com/yannh/kubeconform.git
synced 2026-02-17 17:07:02 +00:00
only expose interfac
This commit is contained in:
parent
9d91ec4aa9
commit
4672ded043
3 changed files with 57 additions and 72 deletions
|
|
@ -90,7 +90,7 @@ func realMain() int {
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
for i := 0; i < cfg.NumberOfWorkers; i++ {
|
for i := 0; i < cfg.NumberOfWorkers; i++ {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(resources <-chan resource.Resource, validationResults chan<- validator.Result, v *validator.Validator) {
|
go func(resources <-chan resource.Resource, validationResults chan<- validator.Result, v validator.Validator) {
|
||||||
for res := range resources {
|
for res := range resources {
|
||||||
validationResults <- v.Validate(res)
|
validationResults <- v.Validate(res)
|
||||||
}
|
}
|
||||||
|
|
@ -106,7 +106,11 @@ func realMain() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err, ok := err.(resource.DiscoveryError); ok {
|
if err, ok := err.(resource.DiscoveryError); ok {
|
||||||
validationResults <- validator.NewError(err.Path, err.Err)
|
validationResults <- validator.Result{
|
||||||
|
Resource: resource.Resource{Path: err.Path},
|
||||||
|
Err: err.Err,
|
||||||
|
Status: validator.Error,
|
||||||
|
}
|
||||||
ctx.Done()
|
ctx.Done()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,15 @@ const (
|
||||||
Empty
|
Empty
|
||||||
)
|
)
|
||||||
|
|
||||||
type Validator struct {
|
// Result contains the details of the result of a resource validation
|
||||||
opts Opts
|
type Result struct {
|
||||||
schemaCache *cache.SchemaCache
|
Resource resource.Resource
|
||||||
schemaDownload func(registries []registry.Registry, kind, version, k8sVersion string) (*gojsonschema.Schema, error)
|
Err error
|
||||||
regs []registry.Registry
|
Status Status
|
||||||
|
}
|
||||||
|
|
||||||
|
type Validator interface {
|
||||||
|
Validate(res resource.Resource) Result
|
||||||
}
|
}
|
||||||
|
|
||||||
type Opts struct {
|
type Opts struct {
|
||||||
|
|
@ -37,28 +41,7 @@ type Opts struct {
|
||||||
IgnoreMissingSchemas bool
|
IgnoreMissingSchemas bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func downloadSchema(registries []registry.Registry, kind, version, k8sVersion string) (*gojsonschema.Schema, error) {
|
func New(schemaLocations []string, opts Opts) Validator {
|
||||||
var err error
|
|
||||||
var schemaBytes []byte
|
|
||||||
|
|
||||||
for _, reg := range registries {
|
|
||||||
schemaBytes, err = reg.DownloadSchema(kind, version, k8sVersion)
|
|
||||||
if err == nil {
|
|
||||||
return gojsonschema.NewSchema(gojsonschema.NewBytesLoader(schemaBytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we get a 404, we try the next registry, but we exit if we get a real failure
|
|
||||||
if _, notfound := err.(*registry.NotFoundError); notfound {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil // No schema found - we don't consider it an error, resource will be skipped
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(schemaLocations []string, opts Opts) *Validator {
|
|
||||||
registries := []registry.Registry{}
|
registries := []registry.Registry{}
|
||||||
for _, schemaLocation := range schemaLocations {
|
for _, schemaLocation := range schemaLocations {
|
||||||
registries = append(registries, registry.New(schemaLocation, opts.Strict, opts.SkipTLS))
|
registries = append(registries, registry.New(schemaLocation, opts.Strict, opts.SkipTLS))
|
||||||
|
|
@ -71,7 +54,7 @@ func New(schemaLocations []string, opts Opts) *Validator {
|
||||||
opts.RejectKinds = map[string]bool{}
|
opts.RejectKinds = map[string]bool{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Validator{
|
return &v{
|
||||||
opts: opts,
|
opts: opts,
|
||||||
schemaDownload: downloadSchema,
|
schemaDownload: downloadSchema,
|
||||||
schemaCache: cache.New(),
|
schemaCache: cache.New(),
|
||||||
|
|
@ -79,14 +62,21 @@ func New(schemaLocations []string, opts Opts) *Validator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validator) Validate(res resource.Resource) Result {
|
type v struct {
|
||||||
|
opts Opts
|
||||||
|
schemaCache *cache.SchemaCache
|
||||||
|
schemaDownload func(registries []registry.Registry, kind, version, k8sVersion string) (*gojsonschema.Schema, error)
|
||||||
|
regs []registry.Registry
|
||||||
|
}
|
||||||
|
|
||||||
|
func (val *v) Validate(res resource.Resource) Result {
|
||||||
skip := func(signature resource.Signature) bool {
|
skip := func(signature resource.Signature) bool {
|
||||||
isSkipKind, ok := v.opts.SkipKinds[signature.Kind]
|
isSkipKind, ok := val.opts.SkipKinds[signature.Kind]
|
||||||
return ok && isSkipKind
|
return ok && isSkipKind
|
||||||
}
|
}
|
||||||
|
|
||||||
reject := func(signature resource.Signature) bool {
|
reject := func(signature resource.Signature) bool {
|
||||||
_, ok := v.opts.RejectKinds[signature.Kind]
|
_, ok := val.opts.RejectKinds[signature.Kind]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,38 +101,34 @@ func (v *Validator) Validate(res resource.Resource) Result {
|
||||||
var schema *gojsonschema.Schema
|
var schema *gojsonschema.Schema
|
||||||
cacheKey := ""
|
cacheKey := ""
|
||||||
|
|
||||||
if v.schemaCache != nil {
|
if val.schemaCache != nil {
|
||||||
cacheKey = cache.Key(sig.Kind, sig.Version, v.opts.KubernetesVersion)
|
cacheKey = cache.Key(sig.Kind, sig.Version, val.opts.KubernetesVersion)
|
||||||
schema, cached = v.schemaCache.Get(cacheKey)
|
schema, cached = val.schemaCache.Get(cacheKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cached {
|
if !cached {
|
||||||
if schema, err = v.schemaDownload(v.regs, sig.Kind, sig.Version, v.opts.KubernetesVersion); err != nil {
|
if schema, err = val.schemaDownload(val.regs, sig.Kind, sig.Version, val.opts.KubernetesVersion); err != nil {
|
||||||
return Result{Resource: res, Err: err, Status: Error}
|
return Result{Resource: res, Err: err, Status: Error}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.schemaCache != nil {
|
if val.schemaCache != nil {
|
||||||
v.schemaCache.Set(cacheKey, schema)
|
val.schemaCache.Set(cacheKey, schema)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if schema == nil {
|
if schema == nil {
|
||||||
if v.opts.IgnoreMissingSchemas {
|
if val.opts.IgnoreMissingSchemas {
|
||||||
return Result{Resource: res, Err: nil, Status: Skipped}
|
return Result{Resource: res, Err: nil, Status: Skipped}
|
||||||
} else {
|
} else {
|
||||||
return Result{Resource: res, Err: fmt.Errorf("could not find schema for %s", sig.Kind), Status: Error}
|
return Result{Resource: res, Err: fmt.Errorf("could not find schema for %s", sig.Kind), Status: Error}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if schema == nil {
|
var r map[string]interface{}
|
||||||
return Result{Resource: res, Status: Skipped, Err: nil}
|
if err := yaml.Unmarshal(res.Bytes, &r); err != nil {
|
||||||
}
|
|
||||||
|
|
||||||
var resource map[string]interface{}
|
|
||||||
if err := yaml.Unmarshal(res.Bytes, &resource); err != nil {
|
|
||||||
return Result{Resource: res, Status: Error, Err: fmt.Errorf("error unmarshalling resource: %s", err)}
|
return Result{Resource: res, Status: Error, Err: fmt.Errorf("error unmarshalling resource: %s", err)}
|
||||||
}
|
}
|
||||||
resourceLoader := gojsonschema.NewGoLoader(resource)
|
resourceLoader := gojsonschema.NewGoLoader(r)
|
||||||
|
|
||||||
results, err := schema.Validate(resourceLoader)
|
results, err := schema.Validate(resourceLoader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -165,14 +151,25 @@ func (v *Validator) Validate(res resource.Resource) Result {
|
||||||
return Result{Resource: res, Status: Invalid, Err: fmt.Errorf("%s", msg)}
|
return Result{Resource: res, Status: Invalid, Err: fmt.Errorf("%s", msg)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidFormat is a type for quickly forcing
|
func downloadSchema(registries []registry.Registry, kind, version, k8sVersion string) (*gojsonschema.Schema, error) {
|
||||||
// new formats on the gojsonschema loader
|
var err error
|
||||||
type ValidFormat struct{}
|
var schemaBytes []byte
|
||||||
|
|
||||||
// ValidFormat is a type for quickly forcing
|
for _, reg := range registries {
|
||||||
// new formats on the gojsonschema loader
|
schemaBytes, err = reg.DownloadSchema(kind, version, k8sVersion)
|
||||||
func (f ValidFormat) IsFormat(input interface{}) bool {
|
if err == nil {
|
||||||
return true
|
return gojsonschema.NewSchema(gojsonschema.NewBytesLoader(schemaBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get a 404, we try the next registry, but we exit if we get a real failure
|
||||||
|
if _, notfound := err.(*registry.NotFoundError); notfound {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil // No schema found - we don't consider it an error, resource will be skipped
|
||||||
}
|
}
|
||||||
|
|
||||||
// From kubeval - let's see if absolutely necessary
|
// From kubeval - let's see if absolutely necessary
|
||||||
|
|
@ -182,19 +179,3 @@ func (f ValidFormat) IsFormat(input interface{}) bool {
|
||||||
// gojsonschema.FormatCheckers.Add("int32", ValidFormat{})
|
// gojsonschema.FormatCheckers.Add("int32", ValidFormat{})
|
||||||
// gojsonschema.FormatCheckers.Add("int-or-string", ValidFormat{})
|
// gojsonschema.FormatCheckers.Add("int-or-string", ValidFormat{})
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// Result contains the details of the result of a resource validation
|
|
||||||
type Result struct {
|
|
||||||
Resource resource.Resource
|
|
||||||
Err error
|
|
||||||
Status Status
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewError is a utility function to generate a validation error
|
|
||||||
func NewError(filename string, err error) Result {
|
|
||||||
return Result{
|
|
||||||
Resource: resource.Resource{Path: filename},
|
|
||||||
Err: err,
|
|
||||||
Status: Error,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ lastName: bar
|
||||||
Error,
|
Error,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
v := Validator{
|
val := v{
|
||||||
opts: Opts{
|
opts: Opts{
|
||||||
SkipKinds: map[string]bool{},
|
SkipKinds: map[string]bool{},
|
||||||
RejectKinds: map[string]bool{},
|
RejectKinds: map[string]bool{},
|
||||||
|
|
@ -149,7 +149,7 @@ lastName: bar
|
||||||
},
|
},
|
||||||
regs: nil,
|
regs: nil,
|
||||||
}
|
}
|
||||||
if got := v.Validate(resource.Resource{Bytes: testCase.rawResource}); got.Status != testCase.expect {
|
if got := val.Validate(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", i, testCase.expect, got.Status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue