diff --git a/cmd/config/internal/commands/cmdcreatesetter.go b/cmd/config/internal/commands/cmdcreatesetter.go index 4e150efb9..d0eef24ba 100644 --- a/cmd/config/internal/commands/cmdcreatesetter.go +++ b/cmd/config/internal/commands/cmdcreatesetter.go @@ -17,6 +17,7 @@ import ( "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/runner" "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/openapi" "sigs.k8s.io/kustomize/kyaml/setters2/settersutil" ) @@ -170,6 +171,10 @@ func (r *CreateSetterRunner) createSetter(c *cobra.Command, args []string) error } func (r *CreateSetterRunner) ExecuteCmd(w io.Writer, pkgPath string) error { + sc, err := openapi.SchemaFromFile(filepath.Join(pkgPath, ext.KRMFileName())) + if err != nil { + return err + } r.CreateSetter = settersutil.SetterCreator{ Name: r.SetterName, SetBy: r.SetBy, @@ -183,9 +188,10 @@ func (r *CreateSetterRunner) ExecuteCmd(w io.Writer, pkgPath string) error { OpenAPIFileName: ext.KRMFileName(), OpenAPIPath: filepath.Join(pkgPath, ext.KRMFileName()), ResourcesPath: pkgPath, + SettersSchema: sc, } - err := r.CreateSetter.Create() + err = r.CreateSetter.Create() if err != nil { // return err if RecurseSubPackages is false if !r.CreateSetter.RecurseSubPackages { diff --git a/cmd/config/internal/commands/cmdcreatesubstitution.go b/cmd/config/internal/commands/cmdcreatesubstitution.go index bba09dc45..ece1869c2 100644 --- a/cmd/config/internal/commands/cmdcreatesubstitution.go +++ b/cmd/config/internal/commands/cmdcreatesubstitution.go @@ -11,6 +11,7 @@ import ( "github.com/spf13/cobra" "sigs.k8s.io/kustomize/cmd/config/ext" "sigs.k8s.io/kustomize/cmd/config/runner" + "sigs.k8s.io/kustomize/kyaml/openapi" "sigs.k8s.io/kustomize/kyaml/setters2/settersutil" ) @@ -66,6 +67,10 @@ func (r *CreateSubstitutionRunner) runE(c *cobra.Command, args []string) error { } func (r *CreateSubstitutionRunner) ExecuteCmd(w io.Writer, pkgPath string) error { + sc, err := openapi.SchemaFromFile(filepath.Join(pkgPath, ext.KRMFileName())) + if err != nil { + return err + } r.CreateSubstitution = settersutil.SubstitutionCreator{ Name: r.CreateSubstitution.Name, FieldName: r.CreateSubstitution.FieldName, @@ -75,9 +80,10 @@ func (r *CreateSubstitutionRunner) ExecuteCmd(w io.Writer, pkgPath string) error OpenAPIFileName: ext.KRMFileName(), OpenAPIPath: filepath.Join(pkgPath, ext.KRMFileName()), ResourcesPath: pkgPath, + SettersSchema: sc, } - err := r.CreateSubstitution.Create() + err = r.CreateSubstitution.Create() if err != nil { // return err if RecurseSubPackages is false if !r.CreateSubstitution.RecurseSubPackages { diff --git a/cmd/config/internal/commands/cmddeletesetter.go b/cmd/config/internal/commands/cmddeletesetter.go index a4ae8e867..fbea3cf8c 100644 --- a/cmd/config/internal/commands/cmddeletesetter.go +++ b/cmd/config/internal/commands/cmddeletesetter.go @@ -13,6 +13,7 @@ import ( "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/runner" "sigs.k8s.io/kustomize/kyaml/fieldmeta" + "sigs.k8s.io/kustomize/kyaml/openapi" "sigs.k8s.io/kustomize/kyaml/setters2/settersutil" ) @@ -72,6 +73,10 @@ func (r *DeleteSetterRunner) runE(c *cobra.Command, args []string) error { } func (r *DeleteSetterRunner) ExecuteCmd(w io.Writer, pkgPath string) error { + sc, err := openapi.SchemaFromFile(filepath.Join(pkgPath, ext.KRMFileName())) + if err != nil { + return err + } r.DeleteSetter = settersutil.DeleterCreator{ Name: r.DeleteSetter.Name, DefinitionPrefix: fieldmeta.SetterDefinitionPrefix, @@ -79,9 +84,10 @@ func (r *DeleteSetterRunner) ExecuteCmd(w io.Writer, pkgPath string) error { OpenAPIFileName: ext.KRMFileName(), OpenAPIPath: filepath.Join(pkgPath, ext.KRMFileName()), ResourcesPath: pkgPath, + SettersSchema: sc, } - err := r.DeleteSetter.Delete() + err = r.DeleteSetter.Delete() if err != nil { // return err if RecurseSubPackages is false if !r.DeleteSetter.RecurseSubPackages { diff --git a/cmd/config/internal/commands/cmddeletesubstitution.go b/cmd/config/internal/commands/cmddeletesubstitution.go index dfd57e36c..a48bf40f9 100644 --- a/cmd/config/internal/commands/cmddeletesubstitution.go +++ b/cmd/config/internal/commands/cmddeletesubstitution.go @@ -12,6 +12,7 @@ import ( "sigs.k8s.io/kustomize/cmd/config/ext" "sigs.k8s.io/kustomize/cmd/config/runner" "sigs.k8s.io/kustomize/kyaml/fieldmeta" + "sigs.k8s.io/kustomize/kyaml/openapi" "sigs.k8s.io/kustomize/kyaml/setters2/settersutil" ) @@ -68,6 +69,10 @@ func (r *DeleteSubstitutionRunner) runE(c *cobra.Command, args []string) error { } func (r *DeleteSubstitutionRunner) ExecuteCmd(w io.Writer, pkgPath string) error { + sc, err := openapi.SchemaFromFile(filepath.Join(pkgPath, ext.KRMFileName())) + if err != nil { + return err + } r.DeleteSubstitution = settersutil.DeleterCreator{ Name: r.DeleteSubstitution.Name, DefinitionPrefix: fieldmeta.SubstitutionDefinitionPrefix, @@ -75,9 +80,10 @@ func (r *DeleteSubstitutionRunner) ExecuteCmd(w io.Writer, pkgPath string) error OpenAPIFileName: ext.KRMFileName(), OpenAPIPath: filepath.Join(pkgPath, ext.KRMFileName()), ResourcesPath: pkgPath, + SettersSchema: sc, } - err := r.DeleteSubstitution.Delete() + err = r.DeleteSubstitution.Delete() if err != nil { // return err if RecurseSubPackages is false if !r.DeleteSubstitution.RecurseSubPackages { diff --git a/cmd/config/internal/commands/cmdlistsetters.go b/cmd/config/internal/commands/cmdlistsetters.go index a93624ba1..2cf8fa22d 100644 --- a/cmd/config/internal/commands/cmdlistsetters.go +++ b/cmd/config/internal/commands/cmdlistsetters.go @@ -16,6 +16,7 @@ import ( "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/runner" "sigs.k8s.io/kustomize/kyaml/fieldmeta" + "sigs.k8s.io/kustomize/kyaml/openapi" "sigs.k8s.io/kustomize/kyaml/setters2" ) @@ -80,9 +81,14 @@ func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error { } func (r *ListSettersRunner) ExecuteCmd(w io.Writer, pkgPath string) error { + sc, err := openapi.SchemaFromFile(filepath.Join(pkgPath, ext.KRMFileName())) + if err != nil { + return err + } r.List = setters2.List{ Name: r.Name, OpenAPIFileName: ext.KRMFileName(), + SettersSchema: sc, } openAPIPath := filepath.Join(pkgPath, ext.KRMFileName()) if err := r.ListSetters(w, openAPIPath, pkgPath); err != nil { diff --git a/cmd/config/runner/runner.go b/cmd/config/runner/runner.go index 3d58d368a..211eb58e4 100644 --- a/cmd/config/runner/runner.go +++ b/cmd/config/runner/runner.go @@ -7,13 +7,11 @@ import ( "fmt" "io" "os" - "path/filepath" "strings" "github.com/go-errors/errors" "github.com/spf13/cobra" "sigs.k8s.io/kustomize/cmd/config/ext" - "sigs.k8s.io/kustomize/kyaml/openapi" "sigs.k8s.io/kustomize/kyaml/pathutil" ) @@ -73,14 +71,6 @@ func (e ExecuteCmdOnPkgs) Execute() error { func (e ExecuteCmdOnPkgs) processPkg(pkgPath string) error { // Add schema present in openAPI file for current package - if e.NeedOpenAPI { - clean, err := openapi.AddSchemaFromFile(filepath.Join(pkgPath, ext.KRMFileName())) - if err != nil { - return err - } - defer clean() - } - if !e.SkipPkgPathPrint { fmt.Fprintf(e.Writer, "%s/\n", pkgPath) } diff --git a/kyaml/fieldmeta/fieldmeta.go b/kyaml/fieldmeta/fieldmeta.go index 63d31174b..83fdff3d5 100644 --- a/kyaml/fieldmeta/fieldmeta.go +++ b/kyaml/fieldmeta/fieldmeta.go @@ -21,6 +21,8 @@ type FieldMeta struct { Schema spec.Schema Extensions XKustomize + + SettersSchema *spec.Schema } type XKustomize struct { @@ -108,7 +110,7 @@ func (fm *FieldMeta) processShortHand(comment string) bool { return false } - if _, err := openapi.Resolve(&setterRef); err == nil { + if _, err := openapi.Resolve(&setterRef, fm.SettersSchema); err == nil { setterErr := fm.Schema.UnmarshalJSON(setterRefBytes) return setterErr == nil } @@ -123,7 +125,7 @@ func (fm *FieldMeta) processShortHand(comment string) bool { return false } - if _, err := openapi.Resolve(&substRef); err == nil { + if _, err := openapi.Resolve(&substRef, fm.SettersSchema); err == nil { substErr := fm.Schema.UnmarshalJSON(substRefBytes) return substErr == nil } diff --git a/kyaml/openapi/openapi.go b/kyaml/openapi/openapi.go index 409cf1d1f..cde50697e 100644 --- a/kyaml/openapi/openapi.go +++ b/kyaml/openapi/openapi.go @@ -70,23 +70,13 @@ const Definitions = "definitions" // The returned clean function is a no-op on error, or else it's a function // that the caller should use to remove the added openAPI definitions from // global schema -func AddSchemaFromFile(path string) (func(), error) { +func SchemaFromFile(path string) (*spec.Schema, error) { object, err := parseOpenAPI(path) if err != nil { - return func() {}, err + return nil, err } - defs, err := definitionRefsFromRNode(object) - if err != nil { - return func() {}, err - } - - clean := func() { - for _, def := range defs { - delete(globalSchema.schema.Definitions, def) - } - } - return clean, addSchemaUsingField(object, SupplementaryOpenAPIFieldName) + return schemaUsingField(object, SupplementaryOpenAPIFieldName) } // DefinitionRefs returns the list of openAPI definition references present in the @@ -121,27 +111,27 @@ func parseOpenAPI(openAPIPath string) (*yaml.RNode, error) { object, err := yaml.Parse(string(b)) if err != nil { - return nil, err + return nil, errors.Errorf("invalid file %q: %v", openAPIPath, err) } return object, nil } // addSchemaUsingField parses the OpenAPI definitions from the specified field. // If field is the empty string, use the whole document as OpenAPI. -func addSchemaUsingField(object *yaml.RNode, field string) error { +func schemaUsingField(object *yaml.RNode, field string) (*spec.Schema, error) { if field != "" { // get the field containing the openAPI m := object.Field(field) if m.IsNilOrEmpty() { // doesn't contain openAPI definitions - return nil + return nil, nil } object = m.Value } oAPI, err := object.String() if err != nil { - return err + return nil, err } // convert the yaml openAPI to a JSON string by unmarshalling it to an @@ -149,19 +139,20 @@ func addSchemaUsingField(object *yaml.RNode, field string) error { var o interface{} err = yaml.Unmarshal([]byte(oAPI), &o) if err != nil { - return err + return nil, err } j, err := json.Marshal(o) if err != nil { - return err + return nil, err } - // add the json schema to the global schema - err = AddSchema(j) + var sc spec.Schema + err = sc.UnmarshalJSON(j) if err != nil { - return err + return nil, err } - return nil + + return &sc, nil } // AddSchema parses s, and adds definitions from s to the global schema. @@ -225,8 +216,8 @@ func toTypeMeta(ext interface{}) (yaml.TypeMeta, bool) { } // Resolve resolves the reference against the global schema -func Resolve(ref *spec.Ref) (*spec.Schema, error) { - return resolve(Schema(), ref) +func Resolve(ref *spec.Ref, schema *spec.Schema) (*spec.Schema, error) { + return resolve(schema, ref) } // Schema returns the global schema @@ -236,13 +227,13 @@ func Schema() *spec.Schema { // GetSchema parses s into a ResourceSchema, resolving References within the // global schema. -func GetSchema(s string) (*ResourceSchema, error) { +func GetSchema(s string, schema *spec.Schema) (*ResourceSchema, error) { var sc spec.Schema if err := sc.UnmarshalJSON([]byte(s)); err != nil { return nil, errors.Wrap(err) } if sc.Ref.String() != "" { - r, err := Resolve(&sc.Ref) + r, err := Resolve(&sc.Ref, schema) if err != nil { return nil, errors.Wrap(err) } @@ -287,7 +278,7 @@ func (rs *ResourceSchema) Elements() *ResourceSchema { } s := *rs.Schema.Items.Schema for s.Ref.String() != "" { - sc, e := Resolve(&s.Ref) + sc, e := Resolve(&s.Ref, Schema()) if e != nil { return nil } @@ -339,7 +330,7 @@ func (rs *ResourceSchema) Field(field string) *ResourceSchema { // resolve the reference to the Schema if the Schema has one for s.Ref.String() != "" { - sc, e := Resolve(&s.Ref) + sc, e := Resolve(&s.Ref, Schema()) if e != nil { return nil } diff --git a/kyaml/openapi/openapi_test.go b/kyaml/openapi/openapi_test.go index a5d38c221..ec2aee4ca 100644 --- a/kyaml/openapi/openapi_test.go +++ b/kyaml/openapi/openapi_test.go @@ -20,7 +20,7 @@ func TestAddSchema(t *testing.T) { if !assert.NoError(t, err) { t.FailNow() } - s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.config.setters.replicas"}`) + s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.config.setters.replicas"}`, Schema()) if !assert.Greater(t, len(globalSchema.schema.Definitions), 200) { t.FailNow() } @@ -31,26 +31,6 @@ func TestAddSchema(t *testing.T) { fmt.Sprintf("%v", s.Schema.Extensions)) } -func TestNoUseBuiltInSchema_AddSchema(t *testing.T) { - // reset package vars - globalSchema = openapiData{} - - SuppressBuiltInSchemaUse() - err := AddSchema(additionalSchema) - if !assert.NoError(t, err) { - t.FailNow() - } - s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.config.setters.replicas"}`) - if !assert.Equal(t, len(globalSchema.schema.Definitions), 1) { - t.FailNow() - } - if !assert.NoError(t, err) { - t.FailNow() - } - assert.Equal(t, `map[x-kustomize:map[setBy:Jane setter:map[name:replicas value:5]]]`, - fmt.Sprintf("%v", s.Schema.Extensions)) -} - var additionalSchema = []byte(` { "definitions": { @@ -124,7 +104,7 @@ func TestSchemaForResourceType(t *testing.T) { } } -func TestAddSchemaFromFile(t *testing.T) { +func TestSchemaFromFile(t *testing.T) { ResetOpenAPI() inputyaml := ` openAPI: @@ -143,93 +123,23 @@ openAPI: t.FailNow() } - clean, err := AddSchemaFromFile(f.Name()) + sc, err := SchemaFromFile(f.Name()) if !assert.NoError(t, err) { t.FailNow() } - defer clean() - s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.cli.setters.image-name"}`) + s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.cli.setters.image-name"}`, sc) if !assert.NoError(t, err) { t.FailNow() } - if !assert.Greater(t, len(globalSchema.schema.Definitions), 200) { + if !assert.Greater(t, len(sc.Definitions), 0) { t.FailNow() } assert.Equal(t, `map[x-k8s-cli:map[setter:map[name:image-name value:nginx]]]`, fmt.Sprintf("%v", s.Schema.Extensions)) } -func TestDeleteSchemaInFile(t *testing.T) { - ResetOpenAPI() - inputyaml := ` -openAPI: - definitions: - io.k8s.cli.setters.image-name: - x-k8s-cli: - setter: - name: image-name - value: "nginx" - ` - f, err := ioutil.TempFile("", "openapi-") - if !assert.NoError(t, err) { - t.FailNow() - } - if !assert.NoError(t, ioutil.WriteFile(f.Name(), []byte(inputyaml), 0600)) { - t.FailNow() - } - - clean, err := AddSchemaFromFile(f.Name()) - if !assert.NoError(t, err) { - t.FailNow() - } - - s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.cli.setters.image-name"}`) - - if !assert.NoError(t, err) { - t.FailNow() - } - if !assert.Greater(t, len(globalSchema.schema.Definitions), 200) { - t.FailNow() - } - assert.Equal(t, `map[x-k8s-cli:map[setter:map[name:image-name value:nginx]]]`, - fmt.Sprintf("%v", s.Schema.Extensions)) - - clean() - - _, err = GetSchema(`{"$ref": "#/definitions/io.k8s.cli.setters.image-name"}`) - - if !assert.Error(t, err) { - t.FailNow() - } - - if !assert.Equal(t, `object has no key "io.k8s.cli.setters.image-name"`, err.Error()) { - t.FailNow() - } -} - -func TestDeleteSchemaInFileNoDefs(t *testing.T) { - ResetOpenAPI() - inputyaml := ` -openAPI: - definitions: - ` - f, err := ioutil.TempFile("", "openapi-") - if !assert.NoError(t, err) { - t.FailNow() - } - if !assert.NoError(t, ioutil.WriteFile(f.Name(), []byte(inputyaml), 0600)) { - t.FailNow() - } - - clean, err := AddSchemaFromFile(f.Name()) - if !assert.NoError(t, err) { - t.FailNow() - } - defer clean() -} - func TestPopulateDefsInOpenAPI_Substitution(t *testing.T) { ResetOpenAPI() inputyaml := ` @@ -265,18 +175,17 @@ openAPI: t.FailNow() } - clean, err := AddSchemaFromFile(f.Name()) + sc, err := SchemaFromFile(f.Name()) if !assert.NoError(t, err) { t.FailNow() } - defer clean() - s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.cli.substitutions.image"}`) + s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.cli.substitutions.image"}`, sc) if !assert.NoError(t, err) { t.FailNow() } - if !assert.Greater(t, len(globalSchema.schema.Definitions), 200) { + if !assert.Equal(t, len(sc.Definitions), 3) { t.FailNow() } @@ -301,13 +210,12 @@ kind: Example t.FailNow() } - clean, err := AddSchemaFromFile(f.Name()) + sc, err := SchemaFromFile(f.Name()) if !assert.NoError(t, err) { t.FailNow() } - defer clean() - if !assert.Equal(t, len(globalSchema.schema.Definitions), 0) { + if !assert.Nil(t, sc) { t.FailNow() } } diff --git a/kyaml/setters2/add.go b/kyaml/setters2/add.go index e67c08d8e..e0b3985e5 100644 --- a/kyaml/setters2/add.go +++ b/kyaml/setters2/add.go @@ -40,6 +40,8 @@ type Add struct { // Count is the number of fields the setter applies to Count int + + SettersSchema *spec.Schema } // Filter implements yaml.Filter @@ -50,7 +52,7 @@ func (a *Add) Filter(object *yaml.RNode) (*yaml.RNode, error) { if a.Ref == "" { return nil, errors.Errorf("must specify ref") } - return object, accept(a, object) + return object, accept(a, object, a.SettersSchema) } func (a *Add) visitSequence(_ *yaml.RNode, _ string, _ *openapi.ResourceSchema) error { @@ -115,7 +117,7 @@ func (a *Add) visitScalar(object *yaml.RNode, p string, _, _ *openapi.ResourceSc // addRef adds the setter/subst ref to the object node as a line comment func (a *Add) addRef(object *yaml.RNode) error { // read the field metadata - fm := fieldmeta.FieldMeta{} + fm := fieldmeta.FieldMeta{SettersSchema: a.SettersSchema} if err := fm.Read(object); err != nil { return err } diff --git a/kyaml/setters2/delete.go b/kyaml/setters2/delete.go index fe56aefe2..5228dfe48 100644 --- a/kyaml/setters2/delete.go +++ b/kyaml/setters2/delete.go @@ -20,11 +20,13 @@ type Delete struct { // DefinitionPrefix is the prefix of the OpenAPI definition type DefinitionPrefix string + + SettersSchema *spec.Schema } // Filter implements yaml.Filter func (d *Delete) Filter(object *yaml.RNode) (*yaml.RNode, error) { - return object, accept(d, object) + return object, accept(d, object, d.SettersSchema) } func (d *Delete) visitSequence(_ *yaml.RNode, _ string, _ *openapi.ResourceSchema) error { @@ -52,7 +54,7 @@ func (d *Delete) visitMapping(object *yaml.RNode, _ string, _ *openapi.ResourceS // visitScalar will remove the reference on each scalar field whose name matches. func (d *Delete) visitScalar(object *yaml.RNode, _ string, _, _ *openapi.ResourceSchema) error { // read the field metadata - fm := fieldmeta.FieldMeta{} + fm := fieldmeta.FieldMeta{SettersSchema: d.SettersSchema} if err := fm.Read(object); err != nil { return err } diff --git a/kyaml/setters2/example_test.go b/kyaml/setters2/example_test.go index fd86f4d7d..9fd15cffa 100644 --- a/kyaml/setters2/example_test.go +++ b/kyaml/setters2/example_test.go @@ -6,129 +6,9 @@ package setters2 import ( "fmt" - "sigs.k8s.io/kustomize/kyaml/openapi" "sigs.k8s.io/kustomize/kyaml/yaml" ) -// ExampleSet demonstrates using Set to replace the current field value in an object -func ExampleSet() { - openapi.ResetOpenAPI() - - // OpenAPI definitions with setter extensions on definitions - schema := ` -{ - "definitions": { - "io.k8s.cli.setters.replicas": { - "x-k8s-cli": { - "setter": { - "name": "replicas", - "value": "4" - } - } - } - } -} -` - // Resource with field referencing OpenAPI definition - deployment := ` -apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx-deployment -spec: - replicas: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"} -` - err := openapi.AddSchema([]byte(schema)) // add the schema definitions - if err != nil { - panic(err) - } - object := yaml.MustParse(deployment) // parse the configuration - err = object.PipeE(&Set{Name: "replicas"}) // set replicas from the setter - if err != nil { - panic(err) - } - - fmt.Println(object.MustString()) - - // Output: - // apiVersion: apps/v1 - // kind: Deployment - // metadata: - // name: nginx-deployment - // spec: - // replicas: 4 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"} -} - -// ExampleSet_Substitution demonstrates using Set to substitute a value into the field of -// an object. Only part of the field value is modified. -func ExampleSet_substitution() { - openapi.ResetOpenAPI() - - // set the version setter - schema := ` -{ - "definitions": { - "io.k8s.cli.setters.version": { - "x-k8s-cli": { - "setter": { - "name": "version", - "value": "1.8.1" - } - } - }, - "io.k8s.cli.substitutions.image": { - "x-k8s-cli": { - "substitution": { - "name": "image", - "pattern": "nginx:VERSION", - "values": [ - {"marker": "VERSION", "ref": "#/definitions/io.k8s.cli.setters.version"} - ] - } - } - } - } -}` - - deployment := ` -apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx-deployment -spec: - template: - spec: - containers: - - name: nginx - image: nginx:1.7.9 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"} -` - - err := openapi.AddSchema([]byte(schema)) // add the schema definitions - if err != nil { - panic(err) - } - object := yaml.MustParse(deployment) // parse the configuration - err = object.PipeE(&Set{Name: "version"}) // set replicas from the setter - if err != nil { - panic(err) - } - - // Print the object with the update value - fmt.Println(object.MustString()) - - // Output: - // apiVersion: apps/v1 - // kind: Deployment - // metadata: - // name: nginx-deployment - // spec: - // template: - // spec: - // containers: - // - name: nginx - // image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"} -} - // ExampleAdd demonstrates adding a setter reference to fields. func ExampleAdd_fieldName() { deployment := ` diff --git a/kyaml/setters2/list.go b/kyaml/setters2/list.go index ed91d98e8..8f7696926 100644 --- a/kyaml/setters2/list.go +++ b/kyaml/setters2/list.go @@ -7,10 +7,10 @@ import ( "sort" "strings" + "github.com/go-openapi/spec" "sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/fieldmeta" "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/openapi" "sigs.k8s.io/kustomize/kyaml/yaml" ) @@ -25,15 +25,12 @@ type List struct { Setters []SetterDefinition Substitutions []SubstitutionDefinition + + SettersSchema *spec.Schema } // ListSetters initializes l.Setters with the setters from the OpenAPI definitions in the file func (l *List) ListSetters(openAPIPath, resourcePath string) error { - clean, err := openapi.AddSchemaFromFile(openAPIPath) - if err != nil { - return err - } - defer clean() y, err := yaml.ReadFile(openAPIPath) if err != nil { return err @@ -43,11 +40,6 @@ func (l *List) ListSetters(openAPIPath, resourcePath string) error { // ListSubst initializes l.Substitutions with the substitutions from the OpenAPI definitions in the file func (l *List) ListSubst(openAPIPath string) error { - clean, err := openapi.AddSchemaFromFile(openAPIPath) - if err != nil { - return err - } - defer clean() y, err := yaml.ReadFile(openAPIPath) if err != nil { return err @@ -193,7 +185,7 @@ func (l *List) listSubst(object *yaml.RNode) error { // set filter is leveraged for this but the resources are not written // back to files as only LocalPackageReader is invoked and not writer func (l *List) count(path, name string) (int, error) { - s := &Set{Name: name} + s := &Set{Name: name, SettersSchema: l.SettersSchema} err := kio.Pipeline{ Inputs: []kio.Reader{&kio.LocalPackageReader{PackagePath: path, PackageFileName: l.OpenAPIFileName}}, Filters: []kio.Filter{kio.FilterAll(s)}, diff --git a/kyaml/setters2/list_test.go b/kyaml/setters2/list_test.go index 291992060..cc8befc89 100644 --- a/kyaml/setters2/list_test.go +++ b/kyaml/setters2/list_test.go @@ -252,7 +252,6 @@ spec: t.Run(test.name, func(t *testing.T) { // reset the openAPI afterward defer openapi.ResetOpenAPI() - initSchema(t, test.openapi) f, err := ioutil.TempFile("", "k8s-cli-") if !assert.NoError(t, err) { @@ -275,7 +274,7 @@ spec: } // invoke the setter - instance := &List{Name: test.setter} + instance := &List{Name: test.setter, SettersSchema: SettersSchema(t, test.openapi)} err = instance.ListSetters(f.Name(), r.Name()) if !assert.NoError(t, err) { t.FailNow() diff --git a/kyaml/setters2/set.go b/kyaml/setters2/set.go index d2b82d276..067f40915 100644 --- a/kyaml/setters2/set.go +++ b/kyaml/setters2/set.go @@ -32,11 +32,13 @@ type Set struct { // SetAll if set to true will set all setters regardless of name SetAll bool + + SettersSchema *spec.Schema } // Filter implements Set as a yaml.Filter func (s *Set) Filter(object *yaml.RNode) (*yaml.RNode, error) { - return object, accept(s, object) + return object, accept(s, object, s.SettersSchema) } // isMatch returns true if the setter with name should have the field @@ -81,9 +83,9 @@ func (s *Set) visitSequence(object *yaml.RNode, p string, schema *openapi.Resour } // visitScalar -func (s *Set) visitScalar(object *yaml.RNode, p string, oa, setterSchema *openapi.ResourceSchema) error { +func (s *Set) visitScalar(object *yaml.RNode, p string, oa, settersSchema *openapi.ResourceSchema) error { // get the openAPI for this field describing how to apply the setter - ext, err := getExtFromComment(setterSchema) + ext, err := getExtFromComment(settersSchema) if err != nil { return err } @@ -97,7 +99,7 @@ func (s *Set) visitScalar(object *yaml.RNode, p string, oa, setterSchema *openap } // perform a direct set of the field if it matches - ok, err := s.set(object, ext, k8sSchema, setterSchema.Schema) + ok, err := s.set(object, ext, k8sSchema, settersSchema.Schema) if err != nil { return err } @@ -177,7 +179,7 @@ func (s *Set) substituteUtil(ext *CliExtension, visited sets.String, nameMatch * if err != nil { return "", errors.Wrap(err) } - def, err := openapi.Resolve(&ref) // resolve the def to its openAPI def + def, err := openapi.Resolve(&ref, s.SettersSchema) // resolve the def to its openAPI def if err != nil { return "", errors.Wrap(err) } diff --git a/kyaml/setters2/set_test.go b/kyaml/setters2/set_test.go index 3387d5468..726d4ec5b 100644 --- a/kyaml/setters2/set_test.go +++ b/kyaml/setters2/set_test.go @@ -4,7 +4,9 @@ package setters2 import ( - "encoding/json" + "io/ioutil" + "os" + "path/filepath" "strings" "testing" @@ -736,7 +738,6 @@ metadata: t.Run(test.name, func(t *testing.T) { // reset the openAPI afterward defer openapi.ResetOpenAPI() - initSchema(t, test.openapi) // parse the input to be modified r, err := yaml.Parse(test.input) @@ -745,7 +746,7 @@ metadata: } // invoke the setter - instance := &Set{Name: test.setter} + instance := &Set{Name: test.setter, SettersSchema: SettersSchema(t, test.openapi)} result, err := instance.Filter(r) if !assert.NoError(t, err) { t.FailNow() @@ -880,7 +881,6 @@ spec: t.Run(test.name, func(t *testing.T) { // reset the openAPI afterward defer openapi.ResetOpenAPI() - initSchema(t, test.openapi) // parse the input to be modified var inputNodes []*yaml.RNode @@ -893,7 +893,7 @@ spec: } // invoke the setter - instance := &Set{Name: test.setter} + instance := &Set{Name: test.setter, SettersSchema: SettersSchema(t, test.openapi)} result, err := SetAll(instance).Filter(inputNodes) if !assert.NoError(t, err) { t.FailNow() @@ -920,44 +920,19 @@ spec: } // initSchema initializes the openAPI with the definitions from s -func initSchema(t *testing.T, s string) { - // parse out the schema from the input openAPI - y, err := yaml.Parse(s) +func SettersSchema(t *testing.T, s string) *spec.Schema { + dir, err := ioutil.TempDir("", "") + assert.NoError(t, err) + defer os.RemoveAll(dir) + err = ioutil.WriteFile(filepath.Join(dir, "Krmfile"), []byte(s), 0600) if !assert.NoError(t, err) { t.FailNow() } - // get the field containing the openAPI - f := y.Field("openAPI") - if !assert.NotNil(t, f) { - t.FailNow() - } - defs, err := f.Value.String() - if !assert.NoError(t, err) { - t.FailNow() - } - - // convert the yaml openAPI to an interface{} - // which can be marshalled into json - var o interface{} - err = yaml.Unmarshal([]byte(defs), &o) - if !assert.NoError(t, err) { - t.FailNow() - } - - // convert the interface{} into a json string - j, err := json.Marshal(o) - if !assert.NoError(t, err) { - t.FailNow() - } - - // reset the openAPI to clear existing definitions - openapi.ResetOpenAPI() - - // add the json schema to the global schema - err = openapi.AddSchema(j) + sc, err := openapi.SchemaFromFile(filepath.Join(dir, "Krmfile")) if !assert.NoError(t, err) { t.FailNow() } + return sc } func TestSetOpenAPI_Filter(t *testing.T) { diff --git a/kyaml/setters2/settersutil/deletecreator_test.go b/kyaml/setters2/settersutil/deletecreator_test.go index d6987908b..600b0a277 100644 --- a/kyaml/setters2/settersutil/deletecreator_test.go +++ b/kyaml/setters2/settersutil/deletecreator_test.go @@ -65,17 +65,17 @@ func TestDeleterCreator_Delete(t *testing.T) { t.FailNow() } + sc, err := openapi.SchemaFromFile(openAPI.Name()) + if !assert.NoError(t, err) { + t.FailNow() + } // add a delete creator dc := DeleterCreator{ Name: "image", DefinitionPrefix: fieldmeta.SetterDefinitionPrefix, + SettersSchema: sc, } - clean, err := openapi.AddSchemaFromFile(openAPI.Name()) - if !assert.NoError(t, err) { - t.FailNow() - } - defer clean() dc.OpenAPIPath = openAPI.Name() dc.ResourcesPath = resource.Name() diff --git a/kyaml/setters2/settersutil/deletercreator.go b/kyaml/setters2/settersutil/deletercreator.go index 0c695e3f5..9cbb82215 100644 --- a/kyaml/setters2/settersutil/deletercreator.go +++ b/kyaml/setters2/settersutil/deletercreator.go @@ -4,8 +4,8 @@ package settersutil import ( + "github.com/go-openapi/spec" "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/openapi" "sigs.k8s.io/kustomize/kyaml/setters2" ) @@ -27,6 +27,8 @@ type DeleterCreator struct { // Path to resources folder ResourcesPath string + + SettersSchema *spec.Schema } func (d DeleterCreator) Delete() error { @@ -38,13 +40,6 @@ func (d DeleterCreator) Delete() error { return err } - // Load the updated definitions - clean, err := openapi.AddSchemaFromFile(d.OpenAPIPath) - if err != nil { - return err - } - defer clean() - // Update the resources with the deleter reference inout := &kio.LocalPackageReadWriter{PackagePath: d.ResourcesPath, PackageFileName: d.OpenAPIFileName} return kio.Pipeline{ @@ -53,6 +48,7 @@ func (d DeleterCreator) Delete() error { &setters2.Delete{ Name: d.Name, DefinitionPrefix: d.DefinitionPrefix, + SettersSchema: d.SettersSchema, })}, Outputs: []kio.Writer{inout}, }.Execute() diff --git a/kyaml/setters2/settersutil/fieldsetter.go b/kyaml/setters2/settersutil/fieldsetter.go index 60a3bae37..26e88cd17 100644 --- a/kyaml/setters2/settersutil/fieldsetter.go +++ b/kyaml/setters2/settersutil/fieldsetter.go @@ -6,8 +6,8 @@ package settersutil import ( "io/ioutil" "os" - "path/filepath" + "github.com/go-openapi/spec" "sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/openapi" "sigs.k8s.io/kustomize/kyaml/setters2" @@ -40,6 +40,8 @@ type FieldSetter struct { RecurseSubPackages bool IsSet bool + + SettersSchema *spec.Schema } func (fs *FieldSetter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { @@ -79,17 +81,17 @@ func (fs FieldSetter) Set() (int, error) { } // Load the updated definitions - clean, err := openapi.AddSchemaFromFile(fs.OpenAPIPath) + sc, err := openapi.SchemaFromFile(fs.OpenAPIPath) if err != nil { return 0, err } - defer clean() + fs.SettersSchema = sc // Update the resources with the new value // Set NoDeleteFiles to true as SetAll will return only the nodes of files which should be updated and // hence, rest of the files should not be deleted inout := &kio.LocalPackageReadWriter{PackagePath: fs.ResourcesPath, NoDeleteFiles: true, PackageFileName: fs.OpenAPIFileName} - s := &setters2.Set{Name: fs.Name} + s := &setters2.Set{Name: fs.Name, SettersSchema: sc} err = kio.Pipeline{ Inputs: []kio.Reader{inout}, Filters: []kio.Filter{setters2.SetAll(s)}, @@ -109,20 +111,12 @@ func (fs FieldSetter) Set() (int, error) { // file and sets all values for the resource configs in the provided destination directories. // If syncOpenAPI is true, the openAPI files in destination directories are also // updated with the setter values in the input openAPI file -func SetAllSetterDefinitions(syncOpenAPI bool, openAPIPath string, dirs ...string) error { - clean, err := openapi.AddSchemaFromFile(openAPIPath) +func SetAllSetterDefinitions(openAPIPath string, dirs ...string) error { + sc, err := openapi.SchemaFromFile(openAPIPath) if err != nil { return err } - defer clean() for _, destDir := range dirs { - if syncOpenAPI { - openAPIFileName := filepath.Base(openAPIPath) - err := syncOpenAPIValuesWithSchema(filepath.Join(destDir, openAPIFileName)) - if err != nil { - return err - } - } rw := &kio.LocalPackageReadWriter{ PackagePath: destDir, // set output won't include resources from files which @@ -134,7 +128,7 @@ func SetAllSetterDefinitions(syncOpenAPI bool, openAPIPath string, dirs ...strin err := kio.Pipeline{ Inputs: []kio.Reader{rw}, // Set all of the setters - Filters: []kio.Filter{setters2.SetAll(&setters2.Set{SetAll: true})}, + Filters: []kio.Filter{setters2.SetAll(&setters2.Set{SetAll: true, SettersSchema: sc})}, Outputs: []kio.Writer{rw}, }.Execute() if err != nil { @@ -143,31 +137,3 @@ func SetAllSetterDefinitions(syncOpenAPI bool, openAPIPath string, dirs ...strin } return nil } - -// syncOpenAPIValuesWithSchema syncs the setter values in global openAPI schema -// with the ones in openAPIPath and writes them back -func syncOpenAPIValuesWithSchema(openAPIPath string) error { - refs, err := openapi.DefinitionRefs(openAPIPath) - if err != nil { - return err - } - for _, ref := range refs { - sch := openapi.Schema().Definitions[ref] - cliExt, err := setters2.GetExtFromSchema(&sch) - if cliExt == nil || cliExt.Setter == nil || err != nil { - // if the ref doesn't exist in global schema or if it is not a setter - // continue, as there might be setters which are not present global schema - continue - } - soa := setters2.SetOpenAPI{ - Name: cliExt.Setter.Name, - Value: cliExt.Setter.Value, - ListValues: cliExt.Setter.ListValues, - IsSet: true, - } - if err := soa.UpdateFile(openAPIPath); err != nil { - return err - } - } - return nil -} diff --git a/kyaml/setters2/settersutil/fieldsetter_test.go b/kyaml/setters2/settersutil/fieldsetter_test.go index 5933271b4..c17d35173 100644 --- a/kyaml/setters2/settersutil/fieldsetter_test.go +++ b/kyaml/setters2/settersutil/fieldsetter_test.go @@ -20,72 +20,9 @@ func TestSetAllSetterDefinitions(t *testing.T) { destOpenAPI string expectedDestFile string expectedDestOpenAPIFile string - syncSchema bool }{ { - name: "set definitions with syncSchema", - syncSchema: true, - srcOpenAPIFile: `openAPI: - definitions: - io.k8s.cli.setters.namespace: - x-k8s-cli: - setter: - name: namespace - value: "project-namespace" - io.k8s.cli.setters.replicas: - x-k8s-cli: - setter: - name: replicas - value: "4"`, - - destFile: `apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx-deployment - namespace: some-other-namespace # {"$ref": "#/definitions/io.k8s.cli.setters.namespace"} -spec: - replicas: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas-new"}`, - - destOpenAPI: `openAPI: - definitions: - io.k8s.cli.setters.namespace: - x-k8s-cli: - setter: - name: namespace - value: "some-other-namespace" - io.k8s.cli.setters.replicas-new: - x-k8s-cli: - setter: - name: replicas-new - value: "3"`, - - expectedDestFile: `apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx-deployment - namespace: project-namespace # {"$ref": "#/definitions/io.k8s.cli.setters.namespace"} -spec: - replicas: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas-new"} -`, - - expectedDestOpenAPIFile: `openAPI: - definitions: - io.k8s.cli.setters.namespace: - x-k8s-cli: - setter: - name: namespace - value: "project-namespace" - isSet: true - io.k8s.cli.setters.replicas-new: - x-k8s-cli: - setter: - name: replicas-new - value: "3" -`, - }, - { - name: "set values only to resources and not the openAPI", - syncSchema: false, + name: "set values only to resources and not the openAPI", srcOpenAPIFile: `openAPI: definitions: io.k8s.cli.setters.namespace: @@ -172,7 +109,7 @@ spec: t.FailNow() } - err = SetAllSetterDefinitions(test.syncSchema, filepath.Join(srcDir, "Krmfile"), destDir) + err = SetAllSetterDefinitions(filepath.Join(srcDir, "Krmfile"), destDir) if !assert.NoError(t, err) { t.FailNow() } diff --git a/kyaml/setters2/settersutil/settercreator.go b/kyaml/setters2/settersutil/settercreator.go index fa8d83013..d07492db0 100644 --- a/kyaml/setters2/settersutil/settercreator.go +++ b/kyaml/setters2/settersutil/settercreator.go @@ -56,6 +56,8 @@ type SetterCreator struct { // Path to resources folder ResourcesPath string + + SettersSchema *spec.Schema } func (c *SetterCreator) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { @@ -75,10 +77,11 @@ func (c SetterCreator) Create() error { // Update the resources with the setter reference inout := &kio.LocalPackageReadWriter{PackagePath: c.ResourcesPath} a := &setters2.Add{ - FieldName: c.FieldName, - FieldValue: c.FieldValue, - Ref: fieldmeta.DefinitionsPrefix + fieldmeta.SetterDefinitionPrefix + c.Name, - Type: c.Type, + FieldName: c.FieldName, + FieldValue: c.FieldValue, + Ref: fieldmeta.DefinitionsPrefix + fieldmeta.SetterDefinitionPrefix + c.Name, + Type: c.Type, + SettersSchema: c.SettersSchema, } err = kio.Pipeline{ Inputs: []kio.Reader{inout}, @@ -103,11 +106,11 @@ func (c SetterCreator) Create() error { } // Load the updated definitions - clean, err := openapi.AddSchemaFromFile(c.OpenAPIPath) + sc, err := openapi.SchemaFromFile(c.OpenAPIPath) if err != nil { return err } - defer clean() + c.SettersSchema = sc // if the setter is of array type write the derived list values back to // openAPI definitions if len(a.ListValues) > 0 { @@ -183,7 +186,7 @@ func (c SetterCreator) validateSetterInfo() error { return err } - subst, _ := openapi.Resolve(&ref) + subst, _ := openapi.Resolve(&ref, c.SettersSchema) // if substitution already exists with the input setter name, throw error if subst != nil { return errors.Errorf("substitution with name %q already exists, "+ @@ -196,7 +199,7 @@ func (c SetterCreator) validateSetterInfo() error { return err } - setter, _ := openapi.Resolve(&ref) + setter, _ := openapi.Resolve(&ref, c.SettersSchema) // if setter already exists with the input setter name, throw error if setter != nil { return errors.Errorf("setter with name %q already exists, "+ diff --git a/kyaml/setters2/settersutil/substitutioncreator.go b/kyaml/setters2/settersutil/substitutioncreator.go index 66909f215..79613dc2b 100644 --- a/kyaml/setters2/settersutil/substitutioncreator.go +++ b/kyaml/setters2/settersutil/substitutioncreator.go @@ -53,6 +53,8 @@ type SubstitutionCreator struct { // Path to resources folder ResourcesPath string + + SettersSchema *spec.Schema } func (c *SubstitutionCreator) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { @@ -64,7 +66,7 @@ func (c SubstitutionCreator) Create() error { if err != nil { return err } - values, err := markersAndRefs(c.Name, c.Pattern) + values, err := c.markersAndRefs(c.Name, c.Pattern) if err != nil { return err } @@ -93,11 +95,11 @@ func (c SubstitutionCreator) Create() error { } // Load the updated definitions - clean, err := openapi.AddSchemaFromFile(c.OpenAPIPath) + sc, err := openapi.SchemaFromFile(c.OpenAPIPath) if err != nil { return err } - defer clean() + c.SettersSchema = sc visited := sets.String{} ref, err := spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SubstitutionDefinitionPrefix + c.Name) @@ -105,7 +107,7 @@ func (c SubstitutionCreator) Create() error { return err } - schema, err := openapi.Resolve(&ref) + schema, err := openapi.Resolve(&ref, c.SettersSchema) if err != nil { return err } @@ -121,14 +123,14 @@ func (c SubstitutionCreator) Create() error { } // Load the updated definitions after setters are created - clean, err = openapi.AddSchemaFromFile(c.OpenAPIPath) + sc, err = openapi.SchemaFromFile(c.OpenAPIPath) if err != nil { return err } - defer clean() + c.SettersSchema = sc // revert openAPI file if there are cycles detected in created input substitution - if err := checkForCycles(ext, visited); err != nil { + if err := c.checkForCycles(ext, visited); err != nil { if writeErr := ioutil.WriteFile(c.OpenAPIPath, curOpenAPI, stat.Mode().Perm()); writeErr != nil { return writeErr } @@ -136,9 +138,10 @@ func (c SubstitutionCreator) Create() error { } a := &setters2.Add{ - FieldName: c.FieldName, - FieldValue: c.FieldValue, - Ref: fieldmeta.DefinitionsPrefix + fieldmeta.SubstitutionDefinitionPrefix + c.Name, + FieldName: c.FieldName, + FieldValue: c.FieldValue, + Ref: fieldmeta.DefinitionsPrefix + fieldmeta.SubstitutionDefinitionPrefix + c.Name, + SettersSchema: c.SettersSchema, } // Update the resources with the substitution reference @@ -158,7 +161,7 @@ func (c SubstitutionCreator) Create() error { // createMarkersAndRefs takes the input pattern, creates setter/substitution markers // and corresponding openAPI refs -func markersAndRefs(substName, pattern string) ([]setters2.Value, error) { +func (c *SubstitutionCreator) markersAndRefs(substName, pattern string) ([]setters2.Value, error) { var values []setters2.Value // extract setter name tokens from pattern enclosed in ${} re := regexp.MustCompile(`\$\{([^}]*)\}`) @@ -180,7 +183,7 @@ func markersAndRefs(substName, pattern string) ([]setters2.Value, error) { } var markerRef string - subst, _ := openapi.Resolve(&ref) + subst, _ := openapi.Resolve(&ref, c.SettersSchema) // check if the substitution exists with the marker name or fall back to creating setter // ref with the name if subst != nil { @@ -246,7 +249,7 @@ func (c SubstitutionCreator) CreateSettersForSubstitution(openAPIPath string) er return nil } -func checkForCycles(ext *setters2.CliExtension, visited sets.String) error { +func (c SubstitutionCreator) checkForCycles(ext *setters2.CliExtension, visited sets.String) error { // check if the substitution has already been visited and throw error as cycles // are not allowed in nested substitutions if visited.Has(ext.Substitution.Name) { @@ -268,7 +271,7 @@ func checkForCycles(ext *setters2.CliExtension, visited sets.String) error { if err != nil { return errors.Wrap(err) } - def, err := openapi.Resolve(&ref) // resolve the def to its openAPI def + def, err := openapi.Resolve(&ref, c.SettersSchema) // resolve the def to its openAPI def if err != nil { return errors.Wrap(err) } @@ -279,7 +282,7 @@ func checkForCycles(ext *setters2.CliExtension, visited sets.String) error { if defExt.Substitution != nil { // parse recursively if it reference is substitution - err := checkForCycles(defExt, visited) + err := c.checkForCycles(defExt, visited) if err != nil { return err } @@ -440,7 +443,7 @@ func (c SubstitutionCreator) validateSubstitutionInfo() error { return err } - subst, _ := openapi.Resolve(&ref) + subst, _ := openapi.Resolve(&ref, c.SettersSchema) // if substitution already exists with the input substitution name, throw error if subst != nil { return errors.Errorf("substitution with name %q already exists", c.Name) @@ -452,7 +455,7 @@ func (c SubstitutionCreator) validateSubstitutionInfo() error { return err } - setter, _ := openapi.Resolve(&ref) + setter, _ := openapi.Resolve(&ref, c.SettersSchema) // if setter already exists with input substitution name, throw error if setter != nil { return errors.Errorf(fmt.Sprintf("setter with name %q already exists, "+ diff --git a/kyaml/setters2/util.go b/kyaml/setters2/util.go index 464e5a6e1..6f95ad0eb 100644 --- a/kyaml/setters2/util.go +++ b/kyaml/setters2/util.go @@ -6,22 +6,22 @@ package setters2 import ( "strings" + "github.com/go-openapi/spec" "sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/fieldmeta" - "sigs.k8s.io/kustomize/kyaml/openapi" ) // CheckRequiredSettersSet iterates through all the setter definitions in openAPI // schema and returns error if any of the setter has required field true and isSet false -func CheckRequiredSettersSet() error { - for key := range openapi.Schema().Definitions { +func CheckRequiredSettersSet(settersSchema *spec.Schema) error { + for key := range settersSchema.Definitions { if strings.Contains(key, fieldmeta.SetterDefinitionPrefix) { - val := openapi.Schema().Definitions[key] + val := settersSchema.Definitions[key] defExt, err := GetExtFromSchema(&val) // parse the extension out of the openAPI if err != nil { return errors.Wrap(err) } - if defExt.Setter.Required && !defExt.Setter.IsSet { + if defExt.Setter != nil && defExt.Setter.Required && !defExt.Setter.IsSet { return errors.Errorf("setter %s is required but not set, "+ "please set it to new value and try again", strings.TrimPrefix(key, fieldmeta.SetterDefinitionPrefix)) } diff --git a/kyaml/setters2/util_test.go b/kyaml/setters2/util_test.go index 40ca5258a..ba1554a5f 100644 --- a/kyaml/setters2/util_test.go +++ b/kyaml/setters2/util_test.go @@ -135,12 +135,6 @@ openAPI: `, expectedError: true, }, - - { - name: "no openAPI", - inputOpenAPIfile: ``, - expectedError: false, - }, } for i := range tests { test := tests[i] @@ -154,14 +148,16 @@ openAPI: if !assert.NoError(t, err) { t.FailNow() } - clean, err := openapi.AddSchemaFromFile(filepath.Join(dir, "Krmfile")) - defer clean() + sc, err := openapi.SchemaFromFile(filepath.Join(dir, "Krmfile")) + if !assert.NoError(t, err) { + t.FailNow() + } if err != nil { // do nothing if openAPI file or schema doesn't exist, CheckRequiredSettersSet() // should not throw any error fmt.Println("Unable to load schema from file, continuing...") } - err = CheckRequiredSettersSet() + err = CheckRequiredSettersSet(sc) if test.expectedError && !assert.Error(t, err) { t.FailNow() } diff --git a/kyaml/setters2/walk.go b/kyaml/setters2/walk.go index 69eb1f447..ca9d39ce3 100644 --- a/kyaml/setters2/walk.go +++ b/kyaml/setters2/walk.go @@ -4,6 +4,7 @@ package setters2 import ( + "github.com/go-openapi/spec" "sigs.k8s.io/kustomize/kyaml/fieldmeta" "sigs.k8s.io/kustomize/kyaml/openapi" "sigs.k8s.io/kustomize/kyaml/yaml" @@ -32,27 +33,27 @@ type visitor interface { } // accept invokes the appropriate function on v for each field in object -func accept(v visitor, object *yaml.RNode) error { +func accept(v visitor, object *yaml.RNode, settersSchema *spec.Schema) error { // get the OpenAPI for the type if it exists - oa := getSchema(object, nil, "") - return acceptImpl(v, object, "", oa) + oa := getSchema(object, nil, "", settersSchema) + return acceptImpl(v, object, "", oa, settersSchema) } // acceptImpl implements accept using recursion -func acceptImpl(v visitor, object *yaml.RNode, p string, oa *openapi.ResourceSchema) error { +func acceptImpl(v visitor, object *yaml.RNode, p string, oa *openapi.ResourceSchema, settersSchema *spec.Schema) error { switch object.YNode().Kind { case yaml.DocumentNode: // Traverse the child of the document - return accept(v, yaml.NewRNode(object.YNode())) + return accept(v, yaml.NewRNode(object.YNode()), settersSchema) case yaml.MappingNode: if err := v.visitMapping(object, p, oa); err != nil { return err } return object.VisitFields(func(node *yaml.MapNode) error { // get the schema for the field and propagate it - fieldSchema := getSchema(node.Key, oa, node.Key.YNode().Value) + fieldSchema := getSchema(node.Key, oa, node.Key.YNode().Value, settersSchema) // Traverse each field value - return acceptImpl(v, node.Value, p+"."+node.Key.YNode().Value, fieldSchema) + return acceptImpl(v, node.Value, p+"."+node.Key.YNode().Value, fieldSchema, settersSchema) }) case yaml.SequenceNode: // get the schema for the sequence node, use the schema provided if not present @@ -61,14 +62,14 @@ func acceptImpl(v visitor, object *yaml.RNode, p string, oa *openapi.ResourceSch return err } // get the schema for the elements - schema := getSchema(object, oa, "") + schema := getSchema(object, oa, "", settersSchema) return object.VisitElements(func(node *yaml.RNode) error { // Traverse each list element - return acceptImpl(v, node, p, schema) + return acceptImpl(v, node, p, schema, settersSchema) }) case yaml.ScalarNode: // Visit the scalar field - fieldSchema := getSchema(object, oa, "") + fieldSchema := getSchema(object, oa, "", settersSchema) return v.visitScalar(object, p, oa, fieldSchema) } return nil @@ -80,14 +81,14 @@ func acceptImpl(v visitor, object *yaml.RNode, p string, oa *openapi.ResourceSch // r is the Node to get the Schema for // s is the provided schema for the field if known // field is the name of the field -func getSchema(r *yaml.RNode, s *openapi.ResourceSchema, field string) *openapi.ResourceSchema { +func getSchema(r *yaml.RNode, s *openapi.ResourceSchema, field string, settersSchema *spec.Schema) *openapi.ResourceSchema { // get the override schema if it exists on the field - fm := fieldmeta.FieldMeta{} + fm := fieldmeta.FieldMeta{SettersSchema: settersSchema} if err := fm.Read(r); err == nil && !fm.IsEmpty() { // per-field schema, this is fine if fm.Schema.Ref.String() != "" { // resolve the reference - s, err := openapi.Resolve(&fm.Schema.Ref) + s, err := openapi.Resolve(&fm.Schema.Ref, settersSchema) if err == nil && s != nil { fm.Schema = *s } diff --git a/kyaml/yaml/walk/map.go b/kyaml/yaml/walk/map.go index 1db97d64a..998af6d32 100644 --- a/kyaml/yaml/walk/map.go +++ b/kyaml/yaml/walk/map.go @@ -113,7 +113,7 @@ func (l Walker) valueIfPresent(node *yaml.MapNode) (*yaml.RNode, *openapi.Resour if err = fm.Read(node.Value); err == nil { s = &openapi.ResourceSchema{Schema: &fm.Schema} if fm.Schema.Ref.String() != "" { - r, err := openapi.Resolve(&fm.Schema.Ref) + r, err := openapi.Resolve(&fm.Schema.Ref, openapi.Schema()) if err == nil && r != nil { s.Schema = r } @@ -127,7 +127,7 @@ func (l Walker) valueIfPresent(node *yaml.MapNode) (*yaml.RNode, *openapi.Resour s = &openapi.ResourceSchema{Schema: &fm.Schema} } if fm.Schema.Ref.String() != "" { - r, err := openapi.Resolve(&fm.Schema.Ref) + r, err := openapi.Resolve(&fm.Schema.Ref, openapi.Schema()) if err == nil && r != nil { s.Schema = r } diff --git a/kyaml/yaml/walk/walk.go b/kyaml/yaml/walk/walk.go index 65ec6c3a8..68de1324e 100644 --- a/kyaml/yaml/walk/walk.go +++ b/kyaml/yaml/walk/walk.go @@ -99,7 +99,7 @@ func (l Walker) GetSchema() *openapi.ResourceSchema { // per-field schema, this is fine if fm.Schema.Ref.String() != "" { // resolve the reference - s, err := openapi.Resolve(&fm.Schema.Ref) + s, err := openapi.Resolve(&fm.Schema.Ref, openapi.Schema()) if err == nil && s != nil { fm.Schema = *s }