mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 17:12:51 +00:00
Sync openAPI setter values with schema
This commit is contained in:
@@ -62,6 +62,8 @@ func SchemaForResourceType(t yaml.TypeMeta) *ResourceSchema {
|
|||||||
// supplementary OpenAPI definitions.
|
// supplementary OpenAPI definitions.
|
||||||
const SupplementaryOpenAPIFieldName = "openAPI"
|
const SupplementaryOpenAPIFieldName = "openAPI"
|
||||||
|
|
||||||
|
const Definitions = "definitions"
|
||||||
|
|
||||||
// AddSchemaFromFile reads the file at path and parses the OpenAPI definitions
|
// AddSchemaFromFile reads the file at path and parses the OpenAPI definitions
|
||||||
// from the field "openAPI"
|
// from the field "openAPI"
|
||||||
func AddSchemaFromFile(path string) error {
|
func AddSchemaFromFile(path string) error {
|
||||||
@@ -70,39 +72,42 @@ func AddSchemaFromFile(path string) error {
|
|||||||
|
|
||||||
// DeleteSchemaInFile reads the file at path and removes all the openAPI definitions
|
// DeleteSchemaInFile reads the file at path and removes all the openAPI definitions
|
||||||
// present in file from global schema
|
// present in file from global schema
|
||||||
func DeleteSchemaInFile(path string) error {
|
func DeleteSchemaInFile(openAPIPath string) error {
|
||||||
b, err := ioutil.ReadFile(path)
|
fields, err := DefinitionRefs(openAPIPath)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
object, err := yaml.Parse(string(b))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
definitions, err := object.Pipe(yaml.Lookup(SupplementaryOpenAPIFieldName, "definitions"))
|
|
||||||
if definitions == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fields, err := definitions.Fields()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
_, ok := globalSchema.schema.Definitions[field]
|
delete(globalSchema.schema.Definitions, field)
|
||||||
if ok {
|
|
||||||
delete(globalSchema.schema.Definitions, field)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefinitionRefs returns the list of openAPI definition references present in the
|
||||||
|
// input openAPIPath
|
||||||
|
func DefinitionRefs(openAPIPath string) ([]string, error) {
|
||||||
|
b, err := ioutil.ReadFile(openAPIPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
object, err := yaml.Parse(string(b))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
definitions, err := object.Pipe(yaml.Lookup(SupplementaryOpenAPIFieldName, Definitions))
|
||||||
|
if definitions == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return definitions.Fields()
|
||||||
|
}
|
||||||
|
|
||||||
// AddSchemaFromFileUsingField reads the file at path and parses the OpenAPI definitions
|
// AddSchemaFromFileUsingField reads the file at path and parses the OpenAPI definitions
|
||||||
// from the specified field. If field is the empty string, use the whole document as
|
// from the specified field. If field is the empty string, use the whole document as
|
||||||
// OpenAPI.
|
// OpenAPI.
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package settersutil
|
|||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||||
@@ -99,16 +100,24 @@ func (fs FieldSetter) Set() (int, error) {
|
|||||||
return s.Count, err
|
return s.Count, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetAllSetterDefinitions reads all the Setter Definitions from the OpenAPI
|
// SetAllSetterDefinitions reads all the Setter Definitions from the input OpenAPI
|
||||||
// file and sets all values in the provided directories.
|
// file and sets all values for the resource configs in the provided destination directories.
|
||||||
func SetAllSetterDefinitions(openAPIPath string, dirs ...string) error {
|
// 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 {
|
||||||
if err := openapi.AddSchemaFromFile(openAPIPath); err != nil {
|
if err := openapi.AddSchemaFromFile(openAPIPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
for _, destDir := range dirs {
|
||||||
for _, dir := range dirs {
|
if syncOpenAPI {
|
||||||
|
openAPIFileName := filepath.Base(openAPIPath)
|
||||||
|
err := syncOpenAPIValuesWithSchema(filepath.Join(destDir, openAPIFileName))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
rw := &kio.LocalPackageReadWriter{
|
rw := &kio.LocalPackageReadWriter{
|
||||||
PackagePath: dir,
|
PackagePath: destDir,
|
||||||
// set output won't include resources from files which
|
// set output won't include resources from files which
|
||||||
//weren't modified. make sure we don't delete them.
|
//weren't modified. make sure we don't delete them.
|
||||||
NoDeleteFiles: true,
|
NoDeleteFiles: true,
|
||||||
@@ -127,3 +136,30 @@ func SetAllSetterDefinitions(openAPIPath string, dirs ...string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
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,
|
||||||
|
}
|
||||||
|
if err := soa.UpdateFile(openAPIPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,14 +6,26 @@ package settersutil
|
|||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSetAllSetterDefinitions(t *testing.T) {
|
func TestSetAllSetterDefinitions(t *testing.T) {
|
||||||
srcOpenAPIFile := `openAPI:
|
var tests = []struct {
|
||||||
|
name string
|
||||||
|
srcOpenAPIFile string
|
||||||
|
destFile string
|
||||||
|
destOpenAPI string
|
||||||
|
expectedDestFile string
|
||||||
|
expectedDestOpenAPIFile string
|
||||||
|
syncSchema bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "set definitions with syncSchema",
|
||||||
|
syncSchema: true,
|
||||||
|
srcOpenAPIFile: `openAPI:
|
||||||
definitions:
|
definitions:
|
||||||
io.k8s.cli.setters.namespace:
|
io.k8s.cli.setters.namespace:
|
||||||
x-k8s-cli:
|
x-k8s-cli:
|
||||||
@@ -24,83 +36,163 @@ func TestSetAllSetterDefinitions(t *testing.T) {
|
|||||||
x-k8s-cli:
|
x-k8s-cli:
|
||||||
setter:
|
setter:
|
||||||
name: replicas
|
name: replicas
|
||||||
value: "4"`
|
value: "4"`,
|
||||||
|
|
||||||
destFile1 := `apiVersion: apps/v1
|
destFile: `apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: nginx-deployment
|
name: nginx-deployment
|
||||||
namespace: some-other-namespace # {"$ref": "#/definitions/io.k8s.cli.setters.namespace"}
|
namespace: some-other-namespace # {"$ref": "#/definitions/io.k8s.cli.setters.namespace"}
|
||||||
spec:
|
spec:
|
||||||
replicas: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}`
|
replicas: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas-new"}`,
|
||||||
|
|
||||||
destFile2 := `apiVersion: apps/v1
|
destOpenAPI: `openAPI:
|
||||||
kind: Deployment
|
definitions:
|
||||||
metadata:
|
io.k8s.cli.setters.namespace:
|
||||||
name: nginx-deployment
|
x-k8s-cli:
|
||||||
namespace: some-other-namespace2 # {"$ref": "#/definitions/io.k8s.cli.setters.namespace"}
|
setter:
|
||||||
spec:
|
name: namespace
|
||||||
replicas: 2 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}`
|
value: "some-other-namespace"
|
||||||
|
io.k8s.cli.setters.replicas-new:
|
||||||
|
x-k8s-cli:
|
||||||
|
setter:
|
||||||
|
name: replicas-new
|
||||||
|
value: "3"`,
|
||||||
|
|
||||||
expectedDestFile := `apiVersion: apps/v1
|
expectedDestFile: `apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: nginx-deployment
|
name: nginx-deployment
|
||||||
namespace: project-namespace # {"$ref": "#/definitions/io.k8s.cli.setters.namespace"}
|
namespace: project-namespace # {"$ref": "#/definitions/io.k8s.cli.setters.namespace"}
|
||||||
spec:
|
spec:
|
||||||
replicas: 4 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}`
|
replicas: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas-new"}
|
||||||
|
`,
|
||||||
|
|
||||||
srcDir, err := ioutil.TempDir("", "")
|
expectedDestOpenAPIFile: `openAPI:
|
||||||
if !assert.NoError(t, err) {
|
definitions:
|
||||||
t.FailNow()
|
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,
|
||||||
|
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"`,
|
||||||
|
|
||||||
destDir1, err := ioutil.TempDir("", "")
|
destFile: `apiVersion: apps/v1
|
||||||
if !assert.NoError(t, err) {
|
kind: Deployment
|
||||||
t.FailNow()
|
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"}`,
|
||||||
|
|
||||||
destDir2, err := ioutil.TempDir("", "")
|
destOpenAPI: `openAPI:
|
||||||
if !assert.NoError(t, err) {
|
definitions:
|
||||||
t.FailNow()
|
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"`,
|
||||||
|
|
||||||
defer os.RemoveAll(srcDir)
|
expectedDestFile: `apiVersion: apps/v1
|
||||||
defer os.RemoveAll(destDir1)
|
kind: Deployment
|
||||||
defer os.RemoveAll(destDir2)
|
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"}
|
||||||
|
`,
|
||||||
|
|
||||||
err = ioutil.WriteFile(srcDir+"/OpenAPIFile", []byte(srcOpenAPIFile), 0600)
|
expectedDestOpenAPIFile: `openAPI:
|
||||||
if !assert.NoError(t, err) {
|
definitions:
|
||||||
t.FailNow()
|
io.k8s.cli.setters.namespace:
|
||||||
}
|
x-k8s-cli:
|
||||||
err = ioutil.WriteFile(destDir1+"/destFile.yaml", []byte(destFile1), 0600)
|
setter:
|
||||||
if !assert.NoError(t, err) {
|
name: namespace
|
||||||
t.FailNow()
|
value: "some-other-namespace"
|
||||||
|
io.k8s.cli.setters.replicas-new:
|
||||||
|
x-k8s-cli:
|
||||||
|
setter:
|
||||||
|
name: replicas-new
|
||||||
|
value: "3"`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
for i := range tests {
|
||||||
|
test := tests[i]
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
srcDir, err := ioutil.TempDir("", "")
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
err = ioutil.WriteFile(destDir2+"/destFile.yaml", []byte(destFile2), 0600)
|
destDir, err := ioutil.TempDir("", "")
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
err = SetAllSetterDefinitions(srcDir+"/OpenAPIFile", destDir1, destDir2)
|
defer os.RemoveAll(srcDir)
|
||||||
if !assert.NoError(t, err) {
|
defer os.RemoveAll(destDir)
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
actualdestFile1, err := ioutil.ReadFile(destDir1 + "/destFile.yaml")
|
err = ioutil.WriteFile(filepath.Join(srcDir, "Krmfile"), []byte(test.srcOpenAPIFile), 0600)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
if !assert.Equal(t, strings.Trim(string(actualdestFile1), "\n"), expectedDestFile) {
|
err = ioutil.WriteFile(filepath.Join(destDir, "destFile.yaml"), []byte(test.destFile), 0600)
|
||||||
t.FailNow()
|
if !assert.NoError(t, err) {
|
||||||
}
|
t.FailNow()
|
||||||
|
}
|
||||||
|
err = ioutil.WriteFile(filepath.Join(destDir, "Krmfile"), []byte(test.destOpenAPI), 0600)
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
actualdestFile2, err := ioutil.ReadFile(destDir2 + "/destFile.yaml")
|
err = SetAllSetterDefinitions(test.syncSchema, filepath.Join(srcDir, "Krmfile"), destDir)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
if !assert.Equal(t, strings.Trim(string(actualdestFile2), "\n"), expectedDestFile) {
|
|
||||||
t.FailNow()
|
actualDestFile1, err := ioutil.ReadFile(filepath.Join(destDir, "destFile.yaml"))
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if !assert.Equal(t, test.expectedDestFile, string(actualDestFile1)) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
actualDestOpenAPIFile1, err := ioutil.ReadFile(filepath.Join(destDir, "Krmfile"))
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assert.Equal(t, test.expectedDestOpenAPIFile, string(actualDestOpenAPIFile1)) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user