mirror of
https://github.com/yannh/kubeconform.git
synced 2026-02-20 10:27:02 +00:00
feat: support set go template delims
This commit is contained in:
parent
84afe70659
commit
74cb3b20fb
8 changed files with 47 additions and 13 deletions
|
|
@ -102,6 +102,8 @@ Usage: ./bin/kubeconform [OPTION]... [FILE OR FOLDER]...
|
||||||
cache schemas downloaded via HTTP to this folder
|
cache schemas downloaded via HTTP to this folder
|
||||||
-debug
|
-debug
|
||||||
print debug information
|
print debug information
|
||||||
|
-delims string
|
||||||
|
the delims for go template parsing
|
||||||
-exit-on-error
|
-exit-on-error
|
||||||
immediately stop execution when the first error is encountered
|
immediately stop execution when the first error is encountered
|
||||||
-h show help information
|
-h show help information
|
||||||
|
|
@ -211,6 +213,7 @@ in each of them, in order, stopping as soon as a matching file is found.
|
||||||
* if the `-schema-location` value ends with `.json` - Kubeconform assumes the value is a **Go templated
|
* if the `-schema-location` value ends with `.json` - Kubeconform assumes the value is a **Go templated
|
||||||
string** that indicates how to search for JSON schemas.
|
string** that indicates how to search for JSON schemas.
|
||||||
* the `-schema-location` value of `default` is an alias for `https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/{{.NormalizedKubernetesVersion}}-standalone{{.StrictSuffix}}/{{.ResourceKind}}{{.KindSuffix}}.json`.
|
* the `-schema-location` value of `default` is an alias for `https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/{{.NormalizedKubernetesVersion}}-standalone{{.StrictSuffix}}/{{.ResourceKind}}{{.KindSuffix}}.json`.
|
||||||
|
* the `-delims` could use an alternative delims when parsing the URL. Such as, when you pass `-delims=[[,,]]`, then it could parse `https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/[[.NormalizedKubernetesVersion]]-standalone[[.StrictSuffix]]/[[.ResourceKind]][[.KindSuffix]].json`
|
||||||
|
|
||||||
**The following command lines are equivalent:**
|
**The following command lines are equivalent:**
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,7 @@ func realMain() int {
|
||||||
KubernetesVersion: cfg.KubernetesVersion,
|
KubernetesVersion: cfg.KubernetesVersion,
|
||||||
Strict: cfg.Strict,
|
Strict: cfg.Strict,
|
||||||
IgnoreMissingSchemas: cfg.IgnoreMissingSchemas,
|
IgnoreMissingSchemas: cfg.IgnoreMissingSchemas,
|
||||||
|
Delims: cfg.Delims,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ type Config struct {
|
||||||
Verbose bool
|
Verbose bool
|
||||||
IgnoreMissingSchemas bool
|
IgnoreMissingSchemas bool
|
||||||
IgnoreFilenamePatterns []string
|
IgnoreFilenamePatterns []string
|
||||||
|
Delims string
|
||||||
Help bool
|
Help bool
|
||||||
Version bool
|
Version bool
|
||||||
}
|
}
|
||||||
|
|
@ -78,6 +79,7 @@ func FromFlags(progName string, args []string) (Config, string, error) {
|
||||||
flags.BoolVar(&c.Verbose, "verbose", false, "print results for all resources (ignored for tap and junit output)")
|
flags.BoolVar(&c.Verbose, "verbose", false, "print results for all resources (ignored for tap and junit output)")
|
||||||
flags.BoolVar(&c.SkipTLS, "insecure-skip-tls-verify", false, "disable verification of the server's SSL certificate. This will make your HTTPS connections insecure")
|
flags.BoolVar(&c.SkipTLS, "insecure-skip-tls-verify", false, "disable verification of the server's SSL certificate. This will make your HTTPS connections insecure")
|
||||||
flags.StringVar(&c.Cache, "cache", "", "cache schemas downloaded via HTTP to this folder")
|
flags.StringVar(&c.Cache, "cache", "", "cache schemas downloaded via HTTP to this folder")
|
||||||
|
flags.StringVar(&c.Delims, "delims", "", "the delims for go template parsing")
|
||||||
flags.BoolVar(&c.Help, "h", false, "show help information")
|
flags.BoolVar(&c.Help, "h", false, "show help information")
|
||||||
flags.BoolVar(&c.Version, "v", false, "show version information")
|
flags.BoolVar(&c.Version, "v", false, "show version information")
|
||||||
flags.Usage = func() {
|
flags.Usage = func() {
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,10 @@ type SchemaRegistry struct {
|
||||||
cache cache.Cache
|
cache cache.Cache
|
||||||
strict bool
|
strict bool
|
||||||
debug bool
|
debug bool
|
||||||
|
delims string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newHTTPRegistry(schemaPathTemplate string, cacheFolder string, strict bool, skipTLS bool, debug bool) (*SchemaRegistry, error) {
|
func newHTTPRegistry(schemaPathTemplate string, cacheFolder string, strict bool, skipTLS bool, debug bool, delims string) (*SchemaRegistry, error) {
|
||||||
reghttp := &http.Transport{
|
reghttp := &http.Transport{
|
||||||
MaxIdleConns: 100,
|
MaxIdleConns: 100,
|
||||||
IdleConnTimeout: 3 * time.Second,
|
IdleConnTimeout: 3 * time.Second,
|
||||||
|
|
@ -57,12 +58,13 @@ func newHTTPRegistry(schemaPathTemplate string, cacheFolder string, strict bool,
|
||||||
cache: filecache,
|
cache: filecache,
|
||||||
strict: strict,
|
strict: strict,
|
||||||
debug: debug,
|
debug: debug,
|
||||||
|
delims: delims,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DownloadSchema downloads the schema for a particular resource from an HTTP server
|
// 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) ([]byte, error) {
|
||||||
url, err := schemaPath(r.schemaPathTemplate, resourceKind, resourceAPIVersion, k8sVersion, r.strict)
|
url, err := schemaPath(r.schemaPathTemplate, resourceKind, resourceAPIVersion, k8sVersion, r.strict, r.delims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,20 +12,22 @@ type LocalRegistry struct {
|
||||||
pathTemplate string
|
pathTemplate string
|
||||||
strict bool
|
strict bool
|
||||||
debug bool
|
debug bool
|
||||||
|
delims string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLocalSchemas creates a new "registry", that will serve schemas from files, given a list of schema filenames
|
// NewLocalSchemas creates a new "registry", that will serve schemas from files, given a list of schema filenames
|
||||||
func newLocalRegistry(pathTemplate string, strict bool, debug bool) (*LocalRegistry, error) {
|
func newLocalRegistry(pathTemplate string, strict bool, debug bool, delims string) (*LocalRegistry, error) {
|
||||||
return &LocalRegistry{
|
return &LocalRegistry{
|
||||||
pathTemplate,
|
pathTemplate,
|
||||||
strict,
|
strict,
|
||||||
debug,
|
debug,
|
||||||
|
delims,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DownloadSchema retrieves the schema from a file for the resource
|
// 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) ([]byte, error) {
|
||||||
schemaFile, err := schemaPath(r.pathTemplate, resourceKind, resourceAPIVersion, k8sVersion, r.strict)
|
schemaFile, err := schemaPath(r.pathTemplate, resourceKind, resourceAPIVersion, k8sVersion, r.strict, r.delims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, nil
|
return []byte{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ func newNotFoundError(err error) *NotFoundError {
|
||||||
func (e *NotFoundError) Error() string { return e.err.Error() }
|
func (e *NotFoundError) Error() string { return e.err.Error() }
|
||||||
func (e *NotFoundError) Retryable() bool { return false }
|
func (e *NotFoundError) Retryable() bool { return false }
|
||||||
|
|
||||||
func schemaPath(tpl, resourceKind, resourceAPIVersion, k8sVersion string, strict bool) (string, error) {
|
func schemaPath(tpl, resourceKind, resourceAPIVersion, k8sVersion string, strict bool, delims string) (string, error) {
|
||||||
normalisedVersion := k8sVersion
|
normalisedVersion := k8sVersion
|
||||||
if normalisedVersion != "master" {
|
if normalisedVersion != "master" {
|
||||||
normalisedVersion = "v" + normalisedVersion
|
normalisedVersion = "v" + normalisedVersion
|
||||||
|
|
@ -51,7 +51,15 @@ func schemaPath(tpl, resourceKind, resourceAPIVersion, k8sVersion string, strict
|
||||||
kindSuffix += "-" + strings.ToLower(groupParts[1])
|
kindSuffix += "-" + strings.ToLower(groupParts[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpl, err := template.New("tpl").Parse(tpl)
|
tmpl := template.New("tpl")
|
||||||
|
|
||||||
|
// in case of some special cases
|
||||||
|
delimsPairs := strings.Split(delims, ",")
|
||||||
|
if len(delimsPairs) == 2 {
|
||||||
|
tmpl = tmpl.Delims(delimsPairs[0], delimsPairs[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, err := tmpl.Parse(tpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
@ -81,7 +89,7 @@ func schemaPath(tpl, resourceKind, resourceAPIVersion, k8sVersion string, strict
|
||||||
return buf.String(), nil
|
return buf.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(schemaLocation string, cache string, strict bool, skipTLS bool, debug bool) (Registry, error) {
|
func New(schemaLocation string, cache string, strict bool, skipTLS bool, debug bool, delims string) (Registry, error) {
|
||||||
if schemaLocation == "default" {
|
if schemaLocation == "default" {
|
||||||
schemaLocation = "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/{{ .NormalizedKubernetesVersion }}-standalone{{ .StrictSuffix }}/{{ .ResourceKind }}{{ .KindSuffix }}.json"
|
schemaLocation = "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/{{ .NormalizedKubernetesVersion }}-standalone{{ .StrictSuffix }}/{{ .ResourceKind }}{{ .KindSuffix }}.json"
|
||||||
} else if !strings.HasSuffix(schemaLocation, "json") { // If we dont specify a full templated path, we assume the paths of our fork of kubernetes-json-schema
|
} else if !strings.HasSuffix(schemaLocation, "json") { // If we dont specify a full templated path, we assume the paths of our fork of kubernetes-json-schema
|
||||||
|
|
@ -89,13 +97,13 @@ func New(schemaLocation string, cache string, strict bool, skipTLS bool, debug b
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to compile the schemaLocation template to ensure it is valid
|
// try to compile the schemaLocation template to ensure it is valid
|
||||||
if _, err := schemaPath(schemaLocation, "Deployment", "v1", "master", true); err != nil {
|
if _, err := schemaPath(schemaLocation, "Deployment", "v1", "master", true, delims); err != nil {
|
||||||
return nil, fmt.Errorf("failed initialising schema location registry: %s", err)
|
return nil, fmt.Errorf("failed initialising schema location registry: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(schemaLocation, "http") {
|
if strings.HasPrefix(schemaLocation, "http") {
|
||||||
return newHTTPRegistry(schemaLocation, cache, strict, skipTLS, debug)
|
return newHTTPRegistry(schemaLocation, cache, strict, skipTLS, debug, delims)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newLocalRegistry(schemaLocation, strict, debug)
|
return newLocalRegistry(schemaLocation, strict, debug, delims)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ func TestSchemaPath(t *testing.T) {
|
||||||
for i, testCase := range []struct {
|
for i, testCase := range []struct {
|
||||||
tpl, resourceKind, resourceAPIVersion, k8sVersion, expected string
|
tpl, resourceKind, resourceAPIVersion, k8sVersion, expected string
|
||||||
strict bool
|
strict bool
|
||||||
|
delims string
|
||||||
errExpected error
|
errExpected error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
|
@ -17,6 +18,7 @@ func TestSchemaPath(t *testing.T) {
|
||||||
"1.16.0",
|
"1.16.0",
|
||||||
"https://kubernetesjsonschema.dev/v1.16.0-standalone-strict/deployment-apps-v1.json",
|
"https://kubernetesjsonschema.dev/v1.16.0-standalone-strict/deployment-apps-v1.json",
|
||||||
true,
|
true,
|
||||||
|
"",
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -26,6 +28,7 @@ func TestSchemaPath(t *testing.T) {
|
||||||
"1.16.0",
|
"1.16.0",
|
||||||
"https://kubernetesjsonschema.dev/v1.16.0-standalone/deployment-apps-v1.json",
|
"https://kubernetesjsonschema.dev/v1.16.0-standalone/deployment-apps-v1.json",
|
||||||
false,
|
false,
|
||||||
|
"",
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -35,6 +38,7 @@ func TestSchemaPath(t *testing.T) {
|
||||||
"1.18.0",
|
"1.18.0",
|
||||||
"https://kubernetesjsonschema.dev/v1.18.0-standalone/service-v1.json",
|
"https://kubernetesjsonschema.dev/v1.18.0-standalone/service-v1.json",
|
||||||
false,
|
false,
|
||||||
|
"",
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -44,10 +48,21 @@ func TestSchemaPath(t *testing.T) {
|
||||||
"master",
|
"master",
|
||||||
"https://kubernetesjsonschema.dev/master-standalone/service-v1.json",
|
"https://kubernetesjsonschema.dev/master-standalone/service-v1.json",
|
||||||
false,
|
false,
|
||||||
|
"",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"https://kubernetesjsonschema.dev/[[ .NormalizedKubernetesVersion ]]-standalone[[ .StrictSuffix ]]/[[ .ResourceKind ]][[ .KindSuffix ]].json",
|
||||||
|
"Service",
|
||||||
|
"v1",
|
||||||
|
"master",
|
||||||
|
"https://kubernetesjsonschema.dev/master-standalone/service-v1.json",
|
||||||
|
false,
|
||||||
|
"[[,]]",
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
got, err := schemaPath(testCase.tpl, testCase.resourceKind, testCase.resourceAPIVersion, testCase.k8sVersion, testCase.strict)
|
got, err := schemaPath(testCase.tpl, testCase.resourceKind, testCase.resourceAPIVersion, testCase.k8sVersion, testCase.strict, testCase.delims)
|
||||||
if err != testCase.errExpected {
|
if err != testCase.errExpected {
|
||||||
t.Errorf("%d - got error %s, expected %s", i+1, err, testCase.errExpected)
|
t.Errorf("%d - got error %s, expected %s", i+1, err, testCase.errExpected)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,8 @@ type Opts struct {
|
||||||
RejectKinds map[string]struct{} // List of resource Kinds to reject
|
RejectKinds map[string]struct{} // List of resource Kinds to reject
|
||||||
KubernetesVersion string // Kubernetes Version - has to match one in https://github.com/instrumenta/kubernetes-json-schema
|
KubernetesVersion string // Kubernetes Version - has to match one in https://github.com/instrumenta/kubernetes-json-schema
|
||||||
Strict bool // thros an error if resources contain undocumented fields
|
Strict bool // thros an error if resources contain undocumented fields
|
||||||
IgnoreMissingSchemas bool // skip a resource if no schema for that resource can be found
|
Delims string
|
||||||
|
IgnoreMissingSchemas bool // skip a resource if no schema for that resource can be found
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new Validator
|
// New returns a new Validator
|
||||||
|
|
@ -62,7 +63,7 @@ func New(schemaLocations []string, opts Opts) (Validator, error) {
|
||||||
|
|
||||||
registries := []registry.Registry{}
|
registries := []registry.Registry{}
|
||||||
for _, schemaLocation := range schemaLocations {
|
for _, schemaLocation := range schemaLocations {
|
||||||
reg, err := registry.New(schemaLocation, opts.Cache, opts.Strict, opts.SkipTLS, opts.Debug)
|
reg, err := registry.New(schemaLocation, opts.Cache, opts.Strict, opts.SkipTLS, opts.Debug, opts.Delims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue