diff --git a/kyaml/openapi/openapi.go b/kyaml/openapi/openapi.go index b4fce67f9..5f1ace8e5 100644 --- a/kyaml/openapi/openapi.go +++ b/kyaml/openapi/openapi.go @@ -296,6 +296,41 @@ func resolve(root interface{}, ref *spec.Ref) (*spec.Schema, error) { } } +func PopulateDefsInOpenAPI(s string) error { + y, err := yaml.Parse(s) + if err != nil { + return err + } + // get the field containing the openAPI + f := y.Field("openAPI") + + defs, err := f.Value.String() + if err != nil { + return err + } + + // convert the yaml openAPI to an interface{} + // which can be marshalled into json + var o interface{} + err = yaml.Unmarshal([]byte(defs), &o) + if err != nil { + return err + } + + // convert the interface{} into a json string + j, err := json.Marshal(o) + if err != nil { + return err + } + + // add the json schema to the global schema + _, err = AddSchema(j) + if err != nil { + return err + } + return nil +} + func rootSchema() *spec.Schema { initSchema() return &globalSchema.schema diff --git a/kyaml/openapi/openapi_test.go b/kyaml/openapi/openapi_test.go index a65bee70b..988818f5f 100644 --- a/kyaml/openapi/openapi_test.go +++ b/kyaml/openapi/openapi_test.go @@ -122,3 +122,80 @@ func TestSchemaForResourceType(t *testing.T) { t.FailNow() } } + +func TestPopulateDefsInOpenAPI_Setter(t *testing.T) { + globalSchema = openapiData{} + inputyaml := ` +openAPI: + definitions: + io.k8s.cli.setters.image-name: + x-k8s-cli: + setter: + name: image-name + value: "nginx" + ` + err := PopulateDefsInOpenAPI(inputyaml) + + 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)) +} + +func TestPopulateDefsInOpenAPI_Substitution(t *testing.T) { + globalSchema = openapiData{} + inputyaml := ` +openAPI: + definitions: + io.k8s.cli.setters.image-name: + x-k8s-cli: + setter: + name: image-name + value: "nginx" + io.k8s.cli.setters.image-tag: + x-k8s-cli: + setter: + name: image-tag + value: "1.8.1" + io.k8s.cli.substitutions.image: + x-k8s-cli: + substitution: + name: image + pattern: IMAGE_NAME:IMAGE_TAG + values: + - marker: "IMAGE_NAME" + ref: "#/definitions/io.k8s.cli.setters.image-name" + - marker: "IMAGE_TAG" + ref: "#/definitions/io.k8s.cli.setters.image-tag" + ` + err := PopulateDefsInOpenAPI(inputyaml) + + if !assert.NoError(t, err) { + t.FailNow() + } + + s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.cli.substitutions.image"}`) + + 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[substitution:map[name:image pattern:IMAGE_NAME:IMAGE_TAG`+ + ` values:[map[marker:IMAGE_NAME ref:#/definitions/io.k8s.cli.setters.image-name]`+ + ` map[marker:IMAGE_TAG ref:#/definitions/io.k8s.cli.setters.image-tag]]]]]`, + fmt.Sprintf("%v", s.Schema.Extensions)) +} diff --git a/kyaml/setters2/setterdefinition.go b/kyaml/setters2/setterdefinition.go new file mode 100644 index 000000000..be8604dcf --- /dev/null +++ b/kyaml/setters2/setterdefinition.go @@ -0,0 +1,56 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package setters2 + +import ( + "io/ioutil" + + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +const DefinitionPrefix = "io.k8s.cli.setters." + +type SetterDefinition struct { + Name string + Value string +} + +func (sd SetterDefinition) AddSetterToFile(path string) error { + b, err := ioutil.ReadFile(path) + if err != nil { + return err + } + y, err := yaml.Parse(string(b)) + if err != nil { + return err + } + if err := y.PipeE(sd); err != nil { + return err + } + out, err := y.String() + if err != nil { + return err + } + if err := ioutil.WriteFile(path, []byte(out), 0600); err != nil { + return err + } + return nil +} + +func (sd SetterDefinition) Filter(object *yaml.RNode) (*yaml.RNode, error) { + key := DefinitionPrefix + sd.Name + + def, err := object.Pipe(yaml.LookupCreate( + yaml.MappingNode, "openAPI", "definitions", key, "x-k8s-cli", "setter")) + if err != nil { + return nil, err + } + if err := def.PipeE(yaml.FieldSetter{Name: "name", StringValue: sd.Name}); err != nil { + return nil, err + } + if err := def.PipeE(yaml.FieldSetter{Name: "value", StringValue: sd.Value}); err != nil { + return nil, err + } + return object, nil +} diff --git a/kyaml/setters2/setterdefinition_test.go b/kyaml/setters2/setterdefinition_test.go new file mode 100644 index 000000000..f233271e2 --- /dev/null +++ b/kyaml/setters2/setterdefinition_test.go @@ -0,0 +1,86 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package setters2 + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +var resourcefile = `apiVersion: resource.dev/v1alpha1 +kind: resourcefile +metadata: + name: hello-world-set +upstream: + type: git + git: + commit: 5c1c019b59299a4f6c7edd1ff5ff54d720621bbe + directory: /package-examples/helloworld-set + ref: v0.1.0 +packageMetadata: + shortDescription: example package using setters` + +func TestAddUpdateSetter(t *testing.T) { + path := os.TempDir() + "/resourcefile" + + //write initial resourcefile to temp path + err := ioutil.WriteFile(path, []byte(resourcefile), 0666) + if !assert.NoError(t, err) { + t.FailNow() + } + + //add a setter definition + sd := SetterDefinition{ + Name: "image", + Value: "1", + } + + err = sd.AddSetterToFile(path) + + if !assert.NoError(t, err) { + t.FailNow() + } + + // update setter definition + sd2 := SetterDefinition{ + Name: "image", + Value: "2", + } + + err = sd2.AddSetterToFile(path) + + if !assert.NoError(t, err) { + t.FailNow() + } + + b, err := ioutil.ReadFile(path) + if err != nil { + t.FailNow() + } + + expected := `apiVersion: resource.dev/v1alpha1 +kind: resourcefile +metadata: + name: hello-world-set +upstream: + type: git + git: + commit: 5c1c019b59299a4f6c7edd1ff5ff54d720621bbe + directory: /package-examples/helloworld-set + ref: v0.1.0 +packageMetadata: + shortDescription: example package using setters +openAPI: + definitions: + io.k8s.cli.setters.image: + x-k8s-cli: + setter: + name: image + value: 2 +` + assert.Equal(t, expected, string(b)) +} diff --git a/kyaml/setters2/substitutiondefinition.go b/kyaml/setters2/substitutiondefinition.go new file mode 100644 index 000000000..17d4ff34e --- /dev/null +++ b/kyaml/setters2/substitutiondefinition.go @@ -0,0 +1,60 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package setters2 + +import ( + "io/ioutil" + + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +type SubstitutionDefinition struct { + Name string `yaml:"name"` + Pattern string `yaml:"pattern"` + Values []Value `yaml:"value"` +} + +type Value struct { + Marker string `yaml:"marker"` + Ref string `yaml:"ref"` +} + +func (subd SubstitutionDefinition) AddSubstitutionToFile(path string) error { + b, err := ioutil.ReadFile(path) + if err != nil { + return err + } + y, err := yaml.Parse(string(b)) + if err != nil { + return err + } + if err := y.PipeE(subd); err != nil { + return err + } + out, err := y.String() + if err != nil { + return err + } + if err := ioutil.WriteFile(path, []byte(out), 0666); err != nil { + return err + } + return nil +} + +func (subd SubstitutionDefinition) Filter(object *yaml.RNode) (*yaml.RNode, error) { + key := DefinitionPrefix + subd.Name + + def, err := object.Pipe(yaml.LookupCreate( + yaml.MappingNode, "openAPI", "definitions", key, "x-k8s-cli", "substitution")) + if err != nil { + return nil, err + } + if err := def.PipeE(yaml.FieldSetter{Name: "name", StringValue: subd.Name}); err != nil { + return nil, err + } + if err := def.PipeE(yaml.FieldSetter{Name: "pattern", StringValue: subd.Pattern}); err != nil { + return nil, err + } + return object, nil +} diff --git a/kyaml/setters2/substitutiondefinition_test.go b/kyaml/setters2/substitutiondefinition_test.go new file mode 100644 index 000000000..9b239bd89 --- /dev/null +++ b/kyaml/setters2/substitutiondefinition_test.go @@ -0,0 +1,86 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package setters2 + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAddUpdateSubstitution(t *testing.T) { + path := os.TempDir() + "/resourcefile" + + //write initial resourcefile to temp path + err := ioutil.WriteFile(path, []byte(resourcefile), 0666) + if !assert.NoError(t, err) { + t.FailNow() + } + + value1 := Value{ + Marker: "IMAGE_NAME", + Ref: "#/definitions/io.k8s.cli.setters.image-name", + } + + value2 := Value{ + Marker: "IMAGE_TAG", + Ref: "#/definitions/io.k8s.cli.setters.image-tag", + } + + values := []Value{value1, value2} + + //add a setter definition + subd := SubstitutionDefinition{ + Name: "image", + Pattern: "IMAGE_NAME:IMAGE_TAG", + Values: values, + } + + err = subd.AddSubstitutionToFile(path) + + if !assert.NoError(t, err) { + t.FailNow() + } + + // update setter definition + subd2 := SubstitutionDefinition{ + Name: "image", + Pattern: "IMAGE_NAME:IMAGE_TAG2", + } + + err = subd2.AddSubstitutionToFile(path) + + if !assert.NoError(t, err) { + t.FailNow() + } + + b, err := ioutil.ReadFile(path) + if err != nil { + t.FailNow() + } + + expected := `apiVersion: resource.dev/v1alpha1 +kind: resourcefile +metadata: + name: hello-world-set +upstream: + type: git + git: + commit: 5c1c019b59299a4f6c7edd1ff5ff54d720621bbe + directory: /package-examples/helloworld-set + ref: v0.1.0 +packageMetadata: + shortDescription: example package using setters +openAPI: + definitions: + io.k8s.cli.setters.image: + x-k8s-cli: + substitution: + name: image + pattern: IMAGE_NAME:IMAGE_TAG2 +` + assert.Equal(t, expected, string(b)) +}