// Copyright 2021 The Kubernetes Authors. // SPDX-License-Identifier: Apache-2.0 package parser import ( iofs "io/fs" "os" "k8s.io/kube-openapi/pkg/validation/spec" "sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/fn/framework" ) const ( // SchemaExtension is the file extension this package requires schema files to have SchemaExtension = ".json" ) // SchemaStrings returns a SchemaParser that will parse the schemas in the given strings. // // This is a helper for use with framework.TemplateProcessor#AdditionalSchemas. Example: // // processor := framework.TemplateProcessor{ // //... // AdditionalSchemas: parser.SchemaStrings(` // { // "definitions": { // "com.example.v1.Foo": { // ... // } // } // } // `), // func SchemaStrings(data ...string) framework.SchemaParser { return framework.SchemaParserFunc(func() ([]*spec.Definitions, error) { var defs []*spec.Definitions for _, content := range data { var schema spec.Schema if err := schema.UnmarshalJSON([]byte(content)); err != nil { return nil, err } else if schema.Definitions == nil { return nil, errors.Errorf("inline schema did not contain any definitions") } defs = append(defs, &schema.Definitions) } return defs, nil }) } // SchemaFiles returns a SchemaParser that will parse the schemas in the given files. // This is a helper for use with framework.TemplateProcessor#AdditionalSchemas. // processor := framework.TemplateProcessor{ // //... // AdditionalSchemas: parser.SchemaFiles("path/to/crd-schemas", "path/to/special-schema.json), // } func SchemaFiles(paths ...string) SchemaParser { return SchemaParser{parser{paths: paths, extensions: []string{SchemaExtension}}} } // SchemaParser is a framework.SchemaParser that can parse files or directories containing openapi schemas. type SchemaParser struct { parser } // Parse implements framework.SchemaParser func (l SchemaParser) Parse() ([]*spec.Definitions, error) { if l.fs == nil { l.fs = os.DirFS(".") } var defs []*spec.Definitions err := l.parse(func(content []byte, name string) error { var schema spec.Schema if err := schema.UnmarshalJSON(content); err != nil { return err } else if schema.Definitions == nil { return errors.Errorf("schema %s did not contain any definitions", name) } defs = append(defs, &schema.Definitions) return nil }) if err != nil { return nil, err } return defs, nil } // FromFS allows you to replace the filesystem in which the parser will look up the given paths. // For example, you can use an embed.FS. func (l SchemaParser) FromFS(fs iofs.FS) SchemaParser { l.parser.fs = fs return l }