mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-07-17 17:52:12 +00:00
Add schema-path flag to input openAPI for setters
This commit is contained in:
@@ -48,6 +48,9 @@ func NewCreateSetterRunner(parent string) *CreateSetterRunner {
|
|||||||
set.Flags().MarkHidden("partial")
|
set.Flags().MarkHidden("partial")
|
||||||
set.Flags().StringVar(&setterVersion, "version", "",
|
set.Flags().StringVar(&setterVersion, "version", "",
|
||||||
"use this version of the setter format")
|
"use this version of the setter format")
|
||||||
|
set.Flags().StringVar(&r.CreateSetter.SchemaPath, "schema-path", "",
|
||||||
|
`openAPI schema file path for setter constraints -- file content `+
|
||||||
|
`e.g. {"type": "string", "maxLength": 15, "enum": ["allowedValue1", "allowedValue2"]}`)
|
||||||
set.Flags().MarkHidden("version")
|
set.Flags().MarkHidden("version")
|
||||||
fixDocs(parent, set)
|
fixDocs(parent, set)
|
||||||
r.Command = set
|
r.Command = set
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ func TestCreateSetterCommand(t *testing.T) {
|
|||||||
name string
|
name string
|
||||||
input string
|
input string
|
||||||
args []string
|
args []string
|
||||||
|
schema string
|
||||||
out string
|
out string
|
||||||
inputOpenAPI string
|
inputOpenAPI string
|
||||||
expectedOpenAPI string
|
expectedOpenAPI string
|
||||||
@@ -85,6 +86,88 @@ openAPI:
|
|||||||
`,
|
`,
|
||||||
err: "substitution with name my-image already exists, substitution and setter can't have same name",
|
err: "substitution with name my-image already exists, substitution and setter can't have same name",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "add replicas with schema",
|
||||||
|
args: []string{"replicas", "3", "--description", "hello world", "--set-by", "me"},
|
||||||
|
schema: `{"maximum": 10, "type": "integer"}`,
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx-deployment
|
||||||
|
spec:
|
||||||
|
replicas: 3
|
||||||
|
`,
|
||||||
|
inputOpenAPI: `
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: Example
|
||||||
|
`,
|
||||||
|
expectedOpenAPI: `
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: Example
|
||||||
|
openAPI:
|
||||||
|
definitions:
|
||||||
|
io.k8s.cli.setters.replicas:
|
||||||
|
maximum: 10
|
||||||
|
type: integer
|
||||||
|
description: hello world
|
||||||
|
x-k8s-cli:
|
||||||
|
setter:
|
||||||
|
name: replicas
|
||||||
|
value: "3"
|
||||||
|
setBy: me
|
||||||
|
`,
|
||||||
|
expectedResources: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx-deployment
|
||||||
|
spec:
|
||||||
|
replicas: 3 # {"$ref":"#/definitions/io.k8s.cli.setters.replicas"}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "add replicas with schema list values",
|
||||||
|
args: []string{"list", "a", "--description", "hello world", "--set-by", "me", "--type", "array"},
|
||||||
|
schema: `{"maxItems": 2, "type": "array", "items": {"type": "string"}}`,
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1beta1
|
||||||
|
kind: Example
|
||||||
|
spec:
|
||||||
|
list:
|
||||||
|
- "a"
|
||||||
|
`,
|
||||||
|
inputOpenAPI: `
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: Example
|
||||||
|
`,
|
||||||
|
expectedOpenAPI: `
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: Example
|
||||||
|
openAPI:
|
||||||
|
definitions:
|
||||||
|
io.k8s.cli.setters.list:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
maxItems: 2
|
||||||
|
type: array
|
||||||
|
description: hello world
|
||||||
|
x-k8s-cli:
|
||||||
|
setter:
|
||||||
|
name: list
|
||||||
|
value: a
|
||||||
|
setBy: me
|
||||||
|
`,
|
||||||
|
expectedResources: `
|
||||||
|
apiVersion: example.com/v1beta1
|
||||||
|
kind: Example
|
||||||
|
spec:
|
||||||
|
list:
|
||||||
|
- "a" # {"$ref":"#/definitions/io.k8s.cli.setters.list"}
|
||||||
|
`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for i := range tests {
|
for i := range tests {
|
||||||
test := tests[i]
|
test := tests[i]
|
||||||
@@ -98,10 +181,27 @@ openAPI:
|
|||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
defer os.Remove(f.Name())
|
defer os.Remove(f.Name())
|
||||||
|
|
||||||
err = ioutil.WriteFile(f.Name(), []byte(test.inputOpenAPI), 0600)
|
err = ioutil.WriteFile(f.Name(), []byte(test.inputOpenAPI), 0600)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if test.schema != "" {
|
||||||
|
sch, err := ioutil.TempFile("", "schema.json")
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
defer os.Remove(sch.Name())
|
||||||
|
|
||||||
|
err = ioutil.WriteFile(sch.Name(), []byte(test.schema), 0600)
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
test.args = append(test.args, "--schema-path", sch.Name())
|
||||||
|
}
|
||||||
|
|
||||||
old := ext.GetOpenAPIFile
|
old := ext.GetOpenAPIFile
|
||||||
defer func() { ext.GetOpenAPIFile = old }()
|
defer func() { ext.GetOpenAPIFile = old }()
|
||||||
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
|
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package setters2
|
package setters2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-openapi/spec"
|
"github.com/go-openapi/spec"
|
||||||
@@ -116,6 +117,9 @@ type SetterDefinition struct {
|
|||||||
// Type is the type of the setter value.
|
// Type is the type of the setter value.
|
||||||
Type string `yaml:"type,omitempty"`
|
Type string `yaml:"type,omitempty"`
|
||||||
|
|
||||||
|
// Schema is the openAPI schema for setter constraints.
|
||||||
|
Schema string `yaml:"schema,omitempty"`
|
||||||
|
|
||||||
// EnumValues is a map of possible setter values to actual field values.
|
// EnumValues is a map of possible setter values to actual field values.
|
||||||
// If EnumValues is specified, then the value set the by user 1) MUST
|
// If EnumValues is specified, then the value set the by user 1) MUST
|
||||||
// be present in the enumValues map as a key, and 2) the map entry value
|
// be present in the enumValues map as a key, and 2) the map entry value
|
||||||
@@ -137,6 +141,26 @@ func (sd SetterDefinition) Filter(object *yaml.RNode) (*yaml.RNode, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
definitions, err := object.Pipe(yaml.Lookup(openapi.SupplementaryOpenAPIFieldName, "definitions"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if sd.Schema != "" {
|
||||||
|
schNode, err := ConvertJSONToYamlNode(sd.Schema)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = definitions.PipeE(yaml.SetField(key, schNode))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// don't write the schema to the extension
|
||||||
|
sd.Schema = ""
|
||||||
|
}
|
||||||
|
|
||||||
if sd.Description != "" {
|
if sd.Description != "" {
|
||||||
err = def.PipeE(yaml.FieldSetter{Name: "description", StringValue: sd.Description})
|
err = def.PipeE(yaml.FieldSetter{Name: "description", StringValue: sd.Description})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -176,6 +200,24 @@ func (sd SetterDefinition) Filter(object *yaml.RNode) (*yaml.RNode, error) {
|
|||||||
return object, nil
|
return object, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConvertJSONToYamlNode parses input json string and returns equivalent yaml node
|
||||||
|
func ConvertJSONToYamlNode(jsonStr string) (*yaml.RNode, error) {
|
||||||
|
var body map[string]interface{}
|
||||||
|
err := json.Unmarshal([]byte(jsonStr), &body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
yml, err := yaml.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ymlStr, err := yaml.Parse(string(yml))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ymlStr, nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetterDefinition may be used to update a files OpenAPI definitions with a new substitution.
|
// SetterDefinition may be used to update a files OpenAPI definitions with a new substitution.
|
||||||
type SubstitutionDefinition struct {
|
type SubstitutionDefinition struct {
|
||||||
// Name is the name of the substitution to create or update
|
// Name is the name of the substitution to create or update
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
package settersutil
|
package settersutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||||
"sigs.k8s.io/kustomize/kyaml/setters2"
|
"sigs.k8s.io/kustomize/kyaml/setters2"
|
||||||
@@ -21,6 +23,8 @@ type SetterCreator struct {
|
|||||||
|
|
||||||
Type string
|
Type string
|
||||||
|
|
||||||
|
SchemaPath string
|
||||||
|
|
||||||
// FieldName if set will add the OpenAPI reference to fields with this name or path
|
// FieldName if set will add the OpenAPI reference to fields with this name or path
|
||||||
// FieldName may be the full name of the field, full path to the field, or the path suffix.
|
// FieldName may be the full name of the field, full path to the field, or the path suffix.
|
||||||
// e.g. all of the following would match spec.template.spec.containers.image --
|
// e.g. all of the following would match spec.template.spec.containers.image --
|
||||||
@@ -35,10 +39,14 @@ type SetterCreator struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c SetterCreator) Create(openAPIPath, resourcesPath string) error {
|
func (c SetterCreator) Create(openAPIPath, resourcesPath string) error {
|
||||||
|
schema, err := schemaFromFile(c.SchemaPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Update the OpenAPI definitions to hace the setter
|
// Update the OpenAPI definitions to hace the setter
|
||||||
sd := setters2.SetterDefinition{
|
sd := setters2.SetterDefinition{
|
||||||
Name: c.Name, Value: c.FieldValue, Description: c.Description, SetBy: c.SetBy,
|
Name: c.Name, Value: c.FieldValue, Description: c.Description, SetBy: c.SetBy,
|
||||||
Type: c.Type,
|
Type: c.Type, Schema: schema,
|
||||||
}
|
}
|
||||||
if err := sd.AddToFile(openAPIPath); err != nil {
|
if err := sd.AddToFile(openAPIPath); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -62,3 +70,15 @@ func (c SetterCreator) Create(openAPIPath, resourcesPath string) error {
|
|||||||
Outputs: []kio.Writer{inout},
|
Outputs: []kio.Writer{inout},
|
||||||
}.Execute()
|
}.Execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// schemaFromFile reads the contents from schemaPath and returns schema
|
||||||
|
func schemaFromFile(schemaPath string) (string, error) {
|
||||||
|
if schemaPath == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
sch, err := ioutil.ReadFile(schemaPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(sch), nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package testutil_test
|
package testutil_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
Reference in New Issue
Block a user