mirror of
https://github.com/yannh/kubeconform.git
synced 2026-04-11 23:44:16 +00:00
refactor validator pkg so it can be usable in a third party app
This commit is contained in:
parent
94f8e9e631
commit
649c2ca4d6
3 changed files with 198 additions and 142 deletions
|
|
@ -3,94 +3,15 @@ package main
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/yannh/kubeconform/pkg/cache"
|
||||
"github.com/yannh/kubeconform/pkg/config"
|
||||
"github.com/yannh/kubeconform/pkg/output"
|
||||
"github.com/yannh/kubeconform/pkg/registry"
|
||||
"github.com/yannh/kubeconform/pkg/resource"
|
||||
"github.com/yannh/kubeconform/pkg/validator"
|
||||
)
|
||||
|
||||
func downloadSchema(registries []registry.Registry, kind, version, k8sVersion string) (*gojsonschema.Schema, error) {
|
||||
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 ValidateResources(resources <-chan resource.Resource, validationResults chan<- validator.Result, regs []registry.Registry, k8sVersion string, c *cache.SchemaCache, skip func(signature resource.Signature) bool, reject func(signature resource.Signature) bool, ignoreMissingSchemas bool) {
|
||||
for res := range resources {
|
||||
sig, err := res.Signature()
|
||||
if err != nil {
|
||||
validationResults <- validator.Result{Resource: res, Err: fmt.Errorf("error while parsing: %s", err), Status: validator.Error}
|
||||
continue
|
||||
}
|
||||
|
||||
if sig.Kind == "" {
|
||||
validationResults <- validator.Result{Resource: res, Err: nil, Status: validator.Empty}
|
||||
continue // We skip resoures that don't have a Kind defined
|
||||
}
|
||||
|
||||
if skip(*sig) {
|
||||
validationResults <- validator.Result{Resource: res, Err: nil, Status: validator.Skipped}
|
||||
continue
|
||||
}
|
||||
|
||||
if reject(*sig) {
|
||||
validationResults <- validator.Result{Resource: res, Err: fmt.Errorf("prohibited resource kind %s", sig.Kind), Status: validator.Error}
|
||||
continue
|
||||
}
|
||||
|
||||
cached := false
|
||||
var schema *gojsonschema.Schema
|
||||
cacheKey := ""
|
||||
|
||||
if c != nil {
|
||||
cacheKey = cache.Key(sig.Kind, sig.Version, k8sVersion)
|
||||
schema, cached = c.Get(cacheKey)
|
||||
}
|
||||
|
||||
if !cached {
|
||||
if schema, err = downloadSchema(regs, sig.Kind, sig.Version, k8sVersion); err != nil {
|
||||
validationResults <- validator.Result{Resource: res, Err: err, Status: validator.Error}
|
||||
continue
|
||||
}
|
||||
|
||||
if c != nil {
|
||||
c.Set(cacheKey, schema)
|
||||
}
|
||||
}
|
||||
|
||||
if schema == nil {
|
||||
if ignoreMissingSchemas {
|
||||
validationResults <- validator.Result{Resource: res, Err: nil, Status: validator.Skipped}
|
||||
} else {
|
||||
validationResults <- validator.Result{Resource: res, Err: fmt.Errorf("could not find schema for %s", sig.Kind), Status: validator.Error}
|
||||
}
|
||||
}
|
||||
|
||||
validationResults <- validator.Validate(res, schema)
|
||||
}
|
||||
}
|
||||
|
||||
func processResults(ctx context.Context, o output.Output, validationResults <-chan validator.Result, exitOnError bool) <-chan bool {
|
||||
success := true
|
||||
result := make(chan bool)
|
||||
|
|
@ -138,27 +59,21 @@ func realMain() int {
|
|||
isStdin = true
|
||||
}
|
||||
|
||||
filter := func(signature resource.Signature) bool {
|
||||
isSkipKind, ok := cfg.SkipKinds[signature.Kind]
|
||||
return ok && isSkipKind
|
||||
}
|
||||
|
||||
reject := func(signature resource.Signature) bool {
|
||||
_, ok := cfg.RejectKinds[signature.Kind]
|
||||
return ok
|
||||
}
|
||||
|
||||
registries := []registry.Registry{}
|
||||
for _, schemaLocation := range cfg.SchemaLocations {
|
||||
registries = append(registries, registry.New(schemaLocation, cfg.Strict, cfg.SkipTLS))
|
||||
}
|
||||
|
||||
var o output.Output
|
||||
if o, err = output.New(cfg.OutputFormat, cfg.Summary, isStdin, cfg.Verbose); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
|
||||
v := validator.New(cfg.SchemaLocations, &validator.Opts{
|
||||
SkipTLS: cfg.SkipTLS,
|
||||
SkipKinds: cfg.SkipKinds,
|
||||
RejectKinds: cfg.RejectKinds,
|
||||
KubernetesVersion: cfg.KubernetesVersion,
|
||||
Strict: cfg.Strict,
|
||||
IgnoreMissingSchemas: cfg.IgnoreMissingSchemas,
|
||||
})
|
||||
|
||||
var resourcesChan <-chan resource.Resource
|
||||
var errors <-chan error
|
||||
validationResults := make(chan validator.Result)
|
||||
|
|
@ -172,14 +87,15 @@ func realMain() int {
|
|||
resourcesChan, errors = resource.FromFiles(ctx, cfg.IgnoreFilenamePatterns, cfg.Files...)
|
||||
}
|
||||
|
||||
c := cache.New()
|
||||
wg := sync.WaitGroup{}
|
||||
for i := 0; i < cfg.NumberOfWorkers; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
ValidateResources(resourcesChan, validationResults, registries, cfg.KubernetesVersion, c, filter, reject, cfg.IgnoreMissingSchemas)
|
||||
go func(resources <-chan resource.Resource, validationResults chan<- validator.Result, v *validator.Validator) {
|
||||
for res := range resources {
|
||||
validationResults <- v.Validate(res)
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}(resourcesChan, validationResults, v)
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue