mirror of
https://github.com/yannh/kubeconform.git
synced 2026-02-19 18:07:02 +00:00
try to validate
This commit is contained in:
parent
fe33d14dc4
commit
96e35cb926
6 changed files with 87 additions and 21 deletions
5
go.mod
5
go.mod
|
|
@ -2,4 +2,7 @@ module github.com/yannh/kubeconform
|
||||||
|
|
||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
require gopkg.in/yaml.v2 v2.3.0
|
require (
|
||||||
|
github.com/xeipuuv/gojsonschema v1.2.0
|
||||||
|
gopkg.in/yaml.v2 v2.3.0
|
||||||
|
)
|
||||||
|
|
|
||||||
10
go.sum
10
go.sum
|
|
@ -1,3 +1,13 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.0/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=
|
||||||
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||||
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||||
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||||
|
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/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|
|
||||||
25
main.go
25
main.go
|
|
@ -1,15 +1,19 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/yannh/kubeconform/pkg/registry"
|
"github.com/yannh/kubeconform/pkg/registry"
|
||||||
"github.com/yannh/kubeconform/pkg/resource"
|
"github.com/yannh/kubeconform/pkg/resource"
|
||||||
|
"github.com/yannh/kubeconform/pkg/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
func realMain() int {
|
func realMain() int {
|
||||||
|
const k8sVersion = "1.18.0"
|
||||||
filename := "fixtures/valid_1.yaml"
|
filename := "fixtures/valid_1.yaml"
|
||||||
|
|
||||||
f, err := os.Open(filename)
|
f, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed opening %s", filename)
|
log.Fatalf("failed opening %s", filename)
|
||||||
|
|
@ -17,21 +21,34 @@ func realMain() int {
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
res, err := resource.Read(f)
|
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 {
|
if err != nil {
|
||||||
log.Printf("failed parsing %s", filename)
|
log.Printf("failed parsing %s", filename)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
r := registry.NewKubernetesRegistry()
|
r := registry.NewKubernetesRegistry()
|
||||||
schema, err := r.DownloadSchema(res.Kind, res.Version, "1.18.0")
|
schema, err := r.DownloadSchema(sig.Kind, sig.Version, k8sVersion)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error downloading Schema: %s")
|
log.Printf("error downloading Schema: %s", err)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("downloaded schema successfully: %s", schema)
|
err = validator.Validate(rawResource, schema)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed validating: %s", err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
log.Printf("resource is valid!: %s", schema)
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,22 +50,22 @@ func (r KubernetesRegistry) schemaURL(resourceKind, resourceAPIVersion, k8sVersi
|
||||||
return fmt.Sprintf("%s/%s-standalone%s/%s%s.json", r.baseURL, normalisedVersion, strictSuffix, strings.ToLower(resourceKind), kindSuffix)
|
return fmt.Sprintf("%s/%s-standalone%s/%s%s.json", r.baseURL, normalisedVersion, strictSuffix, strings.ToLower(resourceKind), kindSuffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r KubernetesRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) (string, error) {
|
func (r KubernetesRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) ([]byte, error) {
|
||||||
url := r.schemaURL(resourceKind, resourceAPIVersion, k8sVersion)
|
url := r.schemaURL(resourceKind, resourceAPIVersion, k8sVersion)
|
||||||
|
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed downloading schema at %s: %s", url, err)
|
return []byte{}, fmt.Errorf("failed downloading schema at %s: %s", url, err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed downloading schema at %s: %s", url, err)
|
return []byte{}, fmt.Errorf("failed downloading schema at %s: %s", url, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("downloaded %s\n", url)
|
fmt.Printf("downloaded %s\n", url)
|
||||||
|
|
||||||
return string(body), nil
|
return body, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,15 @@
|
||||||
package resource
|
package resource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
yaml "gopkg.in/yaml.v2"
|
yaml "gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Resource struct {
|
type Signature struct {
|
||||||
Kind, Version, Namespace string
|
Kind, Version, Namespace string
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Support multi-resources yaml files
|
// TODO: Support multi-resources yaml files
|
||||||
func Read(r io.Reader) (Resource, error) {
|
func SignatureFromBytes(s []byte) (Signature, error) {
|
||||||
s, err := ioutil.ReadAll(r)
|
|
||||||
if err != nil {
|
|
||||||
return Resource{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resource := struct {
|
resource := struct {
|
||||||
APIVersion string `yaml:"apiVersion"`
|
APIVersion string `yaml:"apiVersion"`
|
||||||
Kind string `yaml:"kind"`
|
Kind string `yaml:"kind"`
|
||||||
|
|
@ -24,7 +17,8 @@ func Read(r io.Reader) (Resource, error) {
|
||||||
Namespace string `yaml:"Namespace"`
|
Namespace string `yaml:"Namespace"`
|
||||||
} `yaml:"Metadata"`
|
} `yaml:"Metadata"`
|
||||||
}{}
|
}{}
|
||||||
err = yaml.Unmarshal(s, &resource)
|
err := yaml.Unmarshal(s, &resource)
|
||||||
|
|
||||||
|
return Signature{Kind: resource.Kind, Version: resource.APIVersion, Namespace: resource.Metadata.Namespace}, err
|
||||||
|
}
|
||||||
|
|
||||||
return Resource{Kind: resource.Kind, Version: resource.APIVersion, Namespace: resource.Metadata.Namespace}, err
|
|
||||||
}
|
|
||||||
42
pkg/validator/main.go
Normal file
42
pkg/validator/main.go
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
package validator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/xeipuuv/gojsonschema"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidFormat is a type for quickly forcing
|
||||||
|
// new formats on the gojsonschema loader
|
||||||
|
type ValidFormat struct{}
|
||||||
|
func (f ValidFormat) IsFormat(input interface{}) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func init () {
|
||||||
|
gojsonschema.FormatCheckers.Add("int64", ValidFormat{})
|
||||||
|
gojsonschema.FormatCheckers.Add("byte", ValidFormat{})
|
||||||
|
gojsonschema.FormatCheckers.Add("int32", ValidFormat{})
|
||||||
|
gojsonschema.FormatCheckers.Add("int-or-string", ValidFormat{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Validate(resource interface{}, 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)
|
||||||
|
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 nil
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in a new issue