Merge pull request #2891 from phanimarupaka/ListSettersWithSubPackages

List setters in subpackages
This commit is contained in:
Kubernetes Prow Robot
2020-08-27 13:43:24 -07:00
committed by GitHub
16 changed files with 368 additions and 36 deletions

View File

@@ -12,3 +12,13 @@ import (
var GetOpenAPIFile = func(args []string) (string, error) {
return filepath.Join(args[0], "Krmfile"), nil
}
// OpenAPIFileName returns the name of the file with openAPI definitions
// uses OpenAPIFile function to derive it
func OpenAPIFileName() (string, error) {
openAPIFileName, err := GetOpenAPIFile([]string{"."})
if err != nil {
return "", err
}
return openAPIFileName, nil
}

View File

@@ -13,7 +13,9 @@ import (
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/pathutil"
"sigs.k8s.io/kustomize/kyaml/setters"
"sigs.k8s.io/kustomize/kyaml/setters2"
)
@@ -63,11 +65,35 @@ func (r *ListSettersRunner) preRunE(c *cobra.Command, args []string) error {
func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error {
if setterVersion == "v2" {
if err := r.ListSetters(c, args); err != nil {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
if r.IncludeSubst {
return r.ListSubstitutions(c, args)
openAPIPaths, err := pathutil.SubDirsWithFile(args[0], openAPIFileName)
if err != nil {
return err
}
if len(openAPIPaths) == 0 {
return errors.Errorf("unable to find %s in %s", openAPIFileName, args[0])
}
// list setters for all the subpackages with openAPI file paths
for _, openAPIPath := range openAPIPaths {
r.List = setters2.List{
Name: r.List.Name,
OpenAPIFileName: openAPIFileName,
}
resourcePath := strings.TrimSuffix(openAPIPath, openAPIFileName)
fmt.Fprintf(c.OutOrStdout(), "%s\n", resourcePath)
if err := r.ListSetters(c, openAPIPath, resourcePath); err != nil {
return err
}
if r.IncludeSubst {
if err := r.ListSubstitutions(c, openAPIPath); err != nil {
return err
}
}
}
return nil
}
@@ -75,13 +101,9 @@ func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, lookup(r.Lookup, c, args))
}
func (r *ListSettersRunner) ListSetters(c *cobra.Command, args []string) error {
func (r *ListSettersRunner) ListSetters(c *cobra.Command, openAPIPath, resourcePath string) error {
// use setters v2
path, err := ext.GetOpenAPIFile(args)
if err != nil {
return err
}
if err := r.List.ListSetters(path, args[0]); err != nil {
if err := r.List.ListSetters(openAPIPath, resourcePath); err != nil {
return err
}
table := newTable(c.OutOrStdout(), r.Markdown)
@@ -115,13 +137,9 @@ func (r *ListSettersRunner) ListSetters(c *cobra.Command, args []string) error {
return nil
}
func (r *ListSettersRunner) ListSubstitutions(c *cobra.Command, args []string) error {
func (r *ListSettersRunner) ListSubstitutions(c *cobra.Command, openAPIPath string) error {
// use setters v2
path, err := ext.GetOpenAPIFile(args)
if err != nil {
return err
}
if err := r.List.ListSubst(path); err != nil {
if err := r.List.ListSubst(openAPIPath); err != nil {
return err
}
table := newTable(c.OutOrStdout(), r.Markdown)

View File

@@ -7,11 +7,11 @@ import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/openapi"
)
@@ -408,27 +408,19 @@ openAPI:
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
f, err := ioutil.TempFile("", "k8s-cli-")
dir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
defer os.Remove(f.Name())
old := ext.GetOpenAPIFile
defer func() { ext.GetOpenAPIFile = old }()
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
err = ioutil.WriteFile(f.Name(), []byte(test.openapi), 0600)
if !assert.NoError(t, err) {
t.FailNow()
}
return f.Name(), nil
}
r, err := ioutil.TempFile("", "k8s-cli-*.yaml")
defer os.RemoveAll(dir)
err = ioutil.WriteFile(filepath.Join(dir, "Krmfile"), []byte(test.openapi), 0600)
if !assert.NoError(t, err) {
t.FailNow()
}
defer os.Remove(r.Name())
err = ioutil.WriteFile(r.Name(), []byte(test.input), 0600)
err = ioutil.WriteFile(filepath.Join(dir, "deployment.yaml"), []byte(test.input), 0600)
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -436,18 +428,18 @@ openAPI:
runner := commands.NewListSettersRunner("")
actual := &bytes.Buffer{}
runner.Command.SetOut(actual)
runner.Command.SetArgs(append([]string{r.Name()}, test.args...))
runner.Command.SetArgs(append([]string{dir}, test.args...))
err = runner.Command.Execute()
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Equal(t, test.expected, actual.String()) {
if !assert.Contains(t, actual.String(), test.expected) {
t.FailNow()
}
// make sure that the resources are not altered
actualResources, err := ioutil.ReadFile(r.Name())
actualResources, err := ioutil.ReadFile(filepath.Join(dir, "deployment.yaml"))
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -457,7 +449,7 @@ openAPI:
t.FailNow()
}
actualOpenAPI, err := ioutil.ReadFile(f.Name())
actualOpenAPI, err := ioutil.ReadFile(filepath.Join(dir, "Krmfile"))
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -469,3 +461,57 @@ openAPI:
})
}
}
func TestListSettersSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
args []string
expected string
}{
{
name: "list-replicas",
dataset: "dataset1",
args: []string{"--include-subst"},
expected: `test/testdata/dataset1/mysql/
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
image mysql 1 No
namespace myspace 1 No
tag 1.7.9 1 No
--------------- ----------------- --------------
SUBSTITUTION PATTERN REFERENCES
image-tag ${image}:${tag} [image,tag]
test/testdata/dataset1/mysql/nosetters/
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
test/testdata/dataset1/mysql/storage/
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
namespace myspace 1 No
`,
},
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
// reset the openAPI afterward
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
dir := filepath.Join("test", "testdata", test.dataset)
runner := commands.NewListSettersRunner("")
actual := &bytes.Buffer{}
runner.Command.SetOut(actual)
runner.Command.SetArgs(append([]string{dir}, test.args...))
err := runner.Command.Execute()
if !assert.NoError(t, err) {
t.FailNow()
}
// normalize path format for windows
actualNormalized := strings.Replace(actual.String(), "\\", "/", -1)
if !assert.Equal(t, test.expected, actualNormalized) {
t.FailNow()
}
})
}
}

View File

@@ -178,6 +178,51 @@ items:
outputOverride = `apiVersion: config.kubernetes.io/v1alpha1
kind: ResourceList
items:
- apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-deployment
namespace: myspace # {"$openapi":"namespace"}
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'config/mysql-deployment_deployment.yaml'
spec:
replicas: 3
template:
spec:
containers:
- name: mysql
image: mysql:1.7.9 # {"$openapi":"image-tag"}
- apiVersion: apps/v1
kind: Deployment
metadata:
name: nosetters-deployment
namespace: myspace
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'config/nosetters-deployment_deployment.yaml'
spec:
replicas: 4
template:
spec:
containers:
- name: nosetters
image: nosetters:1.7.7
- apiVersion: apps/v1
kind: Deployment
metadata:
name: storage-deployment
namespace: myspace # {"$openapi":"namespace"}
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'config/storage-deployment_deployment.yaml'
spec:
replicas: 4
template:
spec:
containers:
- name: storage
image: storage:1.7.7
- apiVersion: apps/v1
kind: Deployment
metadata:

View File

@@ -34,7 +34,8 @@ openAPI:
`,
},
expectedStdOut: `
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
./
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
replicas 3 1 No
`,
},

View File

@@ -0,0 +1,33 @@
apiVersion: krm.dev/v1alpha1
kind: Krmfile
metadata:
name: mysql
packageMetadata:
shortDescription: sample description
openAPI:
definitions:
io.k8s.cli.setters.namespace:
x-k8s-cli:
setter:
name: namespace
value: myspace
io.k8s.cli.substitutions.image-tag:
x-k8s-cli:
substitution:
name: image-tag
pattern: ${image}:${tag}
values:
- marker: ${image}
ref: '#/definitions/io.k8s.cli.setters.image'
- marker: ${tag}
ref: '#/definitions/io.k8s.cli.setters.tag'
io.k8s.cli.setters.image:
x-k8s-cli:
setter:
name: image
value: mysql
io.k8s.cli.setters.tag:
x-k8s-cli:
setter:
name: tag
value: 1.7.9

View File

@@ -0,0 +1,12 @@
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: myspace # {"$openapi":"namespace"}
name: mysql-deployment
spec:
replicas: 3
template:
spec:
containers:
- name: mysql
image: mysql:1.7.9 # {"$openapi":"image-tag"}

View File

@@ -0,0 +1,6 @@
apiVersion: krm.dev/v1alpha1
kind: Krmfile
metadata:
name: storage
packageMetadata:
shortDescription: sample description

View File

@@ -0,0 +1,12 @@
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: myspace
name: nosetters-deployment
spec:
replicas: 4
template:
spec:
containers:
- name: nosetters
image: nosetters:1.7.7

View File

@@ -0,0 +1,13 @@
apiVersion: krm.dev/v1alpha1
kind: Krmfile
metadata:
name: storage
packageMetadata:
shortDescription: sample description
openAPI:
definitions:
io.k8s.cli.setters.namespace:
x-k8s-cli:
setter:
name: namespace
value: myspace

View File

@@ -0,0 +1,12 @@
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: myspace # {"$openapi":"namespace"}
name: storage-deployment
spec:
replicas: 4
template:
spec:
containers:
- name: storage
image: storage:1.7.7

View File

@@ -15,6 +15,7 @@ require (
github.com/stretchr/testify v1.4.0
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 // indirect
gopkg.in/yaml.v2 v2.3.0
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71
)

View File

@@ -231,6 +231,8 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

View File

@@ -0,0 +1,33 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package pathutil
import (
"os"
"path/filepath"
"strings"
)
// SubDirsWithFile takes the root directory path and returns all the paths of
// sub-directories which contain file with input fileName including itself
func SubDirsWithFile(root, fileName string) ([]string, error) {
var res []string
err := filepath.Walk(root,
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if strings.HasSuffix(path, fileName) {
if root == "." {
path = root + "/" + path
}
res = append(res, path)
}
return nil
})
if err != nil {
return res, err
}
return res, nil
}

View File

@@ -0,0 +1,83 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package pathutil
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
func TestSubDirsWithFile(t *testing.T) {
dir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
defer os.RemoveAll(dir)
err = createTestDirStructure(dir)
if !assert.NoError(t, err) {
t.FailNow()
}
res, err := SubDirsWithFile(dir, "Krmfile")
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Equal(t, 3, len(res)) {
t.FailNow()
}
}
func TestSubDirsWithFileNoMatch(t *testing.T) {
dir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
defer os.RemoveAll(dir)
res, err := SubDirsWithFile(dir, "non-existent-file.txt")
if !assert.NoError(t, err) {
t.FailNow()
}
var expected []string
if !assert.Equal(t, expected, res) {
t.FailNow()
}
}
func createTestDirStructure(dir string) error {
/*
Adds the folders to the input dir with following structure
dir
├── Krmfile
├── subpkg1
│   ├── Krmfile
│   └── subdir1
└── subpkg2
└── Krmfile
*/
err := os.MkdirAll(filepath.Join(dir, "subpkg1/subdir1"), 0777|os.ModeDir)
if err != nil {
return err
}
err = os.MkdirAll(filepath.Join(dir, "subpkg2"), 0777|os.ModeDir)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg1", "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg2", "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
return nil
}

View File

@@ -15,9 +15,13 @@ import (
)
// List lists the setters specified in the OpenAPI
// excludes the subpackages which contain file with
// name OpenAPIFileName in them
type List struct {
Name string
OpenAPIFileName string
Setters []SetterDefinition
Substitutions []SubstitutionDefinition
@@ -181,12 +185,13 @@ func (l *List) listSubst(object *yaml.RNode) error {
}
// count returns the number of fields set by the setter with name
// this excludes all the subpackages with openAPI file in them
// 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}
err := kio.Pipeline{
Inputs: []kio.Reader{&kio.LocalPackageReader{PackagePath: path}},
Inputs: []kio.Reader{&kio.LocalPackageReader{PackagePath: path, PackageFileName: l.OpenAPIFileName}},
Filters: []kio.Filter{kio.FilterAll(s)},
}.Execute()