diff --git a/cmd/config/go.mod b/cmd/config/go.mod index 3743484ce..8b5dcb00f 100644 --- a/cmd/config/go.mod +++ b/cmd/config/go.mod @@ -13,7 +13,7 @@ require ( github.com/stretchr/testify v1.4.0 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 // indirect k8s.io/apimachinery v0.17.0 - sigs.k8s.io/kustomize/kyaml v0.0.0 + sigs.k8s.io/kustomize/kyaml v0.1.7 ) -replace sigs.k8s.io/kustomize/kyaml v0.0.0 => ../../kyaml +replace sigs.k8s.io/kustomize/kyaml v0.1.7 => ../../kyaml diff --git a/cmd/config/go.sum b/cmd/config/go.sum index 3dc08d7c2..23657cce4 100644 --- a/cmd/config/go.sum +++ b/cmd/config/go.sum @@ -173,6 +173,7 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -225,6 +226,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL 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/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/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= diff --git a/cmd/config/internal/commands/cmdlistsetters.go b/cmd/config/internal/commands/cmdlistsetters.go index 566bcbd5b..d88a4802d 100644 --- a/cmd/config/internal/commands/cmdlistsetters.go +++ b/cmd/config/internal/commands/cmdlistsetters.go @@ -59,42 +59,83 @@ func (r *ListSettersRunner) preRunE(c *cobra.Command, args []string) error { func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error { if setterVersion == "v2" { - // use setters v2 - path, err := ext.GetOpenAPIFile(args) - if err != nil { + if err := r.ListSetters(c, args); err != nil { return err } - if err := r.List.List(path, args[0]); err != nil { - return err - } - table := newTable(c.OutOrStdout(), r.Markdown) - table.SetHeader([]string{"NAME", "VALUE", "SET BY", "DESCRIPTION", "COUNT"}) - for i := range r.List.Setters { - s := r.List.Setters[i] - v := s.Value - - // if the setter is for a list, populate the values - if len(s.ListValues) > 0 { - v = strings.Join(s.ListValues, ",") - v = fmt.Sprintf("[%s]", v) - } - table.Append([]string{ - s.Name, v, s.SetBy, s.Description, fmt.Sprintf("%d", s.Count)}) - } - table.Render() - - if len(r.List.Setters) == 0 { - // exit non-0 if no matching setters are found - if ExitOnError { - os.Exit(1) - } - } - return nil + return r.ListSubstitutions(c, args) } return handleError(c, lookup(r.Lookup, c, args)) } +func (r *ListSettersRunner) ListSetters(c *cobra.Command, args []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 { + return err + } + table := newTable(c.OutOrStdout(), r.Markdown) + table.SetHeader([]string{"NAME", "VALUE", "SET BY", "DESCRIPTION", "COUNT"}) + for i := range r.List.Setters { + s := r.List.Setters[i] + v := s.Value + + // if the setter is for a list, populate the values + if len(s.ListValues) > 0 { + v = strings.Join(s.ListValues, ",") + v = fmt.Sprintf("[%s]", v) + } + table.Append([]string{ + s.Name, v, s.SetBy, s.Description, fmt.Sprintf("%d", s.Count)}) + } + table.Render() + + if len(r.List.Setters) == 0 { + // exit non-0 if no matching setters are found + if ExitOnError { + os.Exit(1) + } + } + return nil +} + +func (r *ListSettersRunner) ListSubstitutions(c *cobra.Command, args []string) error { + // use setters v2 + path, err := ext.GetOpenAPIFile(args) + if err != nil { + return err + } + if err := r.List.ListSubst(path); err != nil { + return err + } + table := newTable(c.OutOrStdout(), r.Markdown) + table.SetHeader([]string{"SUBSTITUTION", "PATTERN", "SETTERS"}) + for i := range r.List.Substitutions { + s := r.List.Substitutions[i] + setters := "" + for _, value := range s.Values { + setter := strings.TrimPrefix(value.Ref, setters2.DefinitionsPrefix+setters2.SetterDefinitionPrefix) + setters = setters + "," + setter + } + setters = fmt.Sprintf("[%s]", strings.TrimPrefix(setters, ",")) + table.Append([]string{ + s.Name, s.Pattern, setters}) + } + if len(r.List.Substitutions) == 0 { + // exit non-0 if no matching substitutions are found + if ExitOnError { + os.Exit(1) + } + } else { + table.Render() + } + + return nil +} + func newTable(o io.Writer, m bool) *tablewriter.Table { table := tablewriter.NewWriter(o) table.SetRowLine(false) diff --git a/cmd/config/internal/commands/cmdlistsetters_test.go b/cmd/config/internal/commands/cmdlistsetters_test.go index dbd97a2b4..77d475a73 100644 --- a/cmd/config/internal/commands/cmdlistsetters_test.go +++ b/cmd/config/internal/commands/cmdlistsetters_test.go @@ -104,6 +104,8 @@ spec: image nginx me2 hello world 2 2 replicas 3 me1 hello world 1 1 tag 1.7.9 me3 hello world 3 1 + SUBSTITUTION PATTERN SETTERS + image IMAGE:TAG [image,tag] `, }, { @@ -176,6 +178,8 @@ spec: image nginx me2 hello world 2 3 replicas 3 me1 hello world 1 2 tag 1.7.9 me3 hello world 3 2 + SUBSTITUTION PATTERN SETTERS + image IMAGE:TAG [image,tag] `, }, { @@ -247,6 +251,8 @@ spec: `, expected: ` NAME VALUE SET BY DESCRIPTION COUNT image nginx me2 hello world 2 3 + SUBSTITUTION PATTERN SETTERS + image IMAGE:TAG [image,tag] `, }, } diff --git a/kyaml/setters2/list.go b/kyaml/setters2/list.go index a0436732f..ca00f944c 100644 --- a/kyaml/setters2/list.go +++ b/kyaml/setters2/list.go @@ -18,10 +18,12 @@ type List struct { Name string Setters []SetterDefinition + + Substitutions []SubstitutionDefinition } -// List initializes l.Setters with the setters from the OpenAPI definitions in the file -func (l *List) List(openAPIPath, resourcePath string) error { +// ListSetters initializes l.Setters with the setters from the OpenAPI definitions in the file +func (l *List) ListSetters(openAPIPath, resourcePath string) error { if err := openapi.AddSchemaFromFile(openAPIPath); err != nil { return err } @@ -29,10 +31,22 @@ func (l *List) List(openAPIPath, resourcePath string) error { if err != nil { return err } - return l.list(y, resourcePath) + return l.listSetters(y, resourcePath) } -func (l *List) list(object *yaml.RNode, resourcePath string) error { +// ListSubst initializes l.Substitutions with the substitutions from the OpenAPI definitions in the file +func (l *List) ListSubst(openAPIPath string) error { + if err := openapi.AddSchemaFromFile(openAPIPath); err != nil { + return err + } + y, err := yaml.ReadFile(openAPIPath) + if err != nil { + return err + } + return l.listSubst(y) +} + +func (l *List) listSetters(object *yaml.RNode, resourcePath string) error { // read the OpenAPI definitions def, err := object.Pipe(yaml.LookupCreate(yaml.MappingNode, "openAPI", "definitions")) if err != nil { @@ -105,6 +119,66 @@ func (l *List) list(object *yaml.RNode, resourcePath string) error { return nil } +func (l *List) listSubst(object *yaml.RNode) error { + // read the OpenAPI definitions + def, err := object.Pipe(yaml.LookupCreate(yaml.MappingNode, "openAPI", "definitions")) + if err != nil { + return err + } + if yaml.IsEmpty(def) { + return nil + } + + // iterate over definitions -- find those that are substitutions + err = def.VisitFields(func(node *yaml.MapNode) error { + subst := SubstitutionDefinition{} + + // the definition key -- contains the substitution name + key := node.Key.YNode().Value + + if !strings.HasPrefix(key, SubstitutionDefinitionPrefix) { + // not a substitution -- doesn't have the right prefix + return nil + } + + substNode, err := node.Value.Pipe(yaml.Lookup(K8sCliExtensionKey, "substitution")) + if err != nil { + return err + } + if yaml.IsEmpty(substNode) { + // has the substitution prefix, but missing the setter extension + return errors.Errorf("missing x-k8s-cli.substitution for %s", key) + } + + // unmarshal the yaml for the substitution extension into the definition struct + b, err := substNode.String() + if err != nil { + return err + } + if err := yaml.Unmarshal([]byte(b), &subst); err != nil { + return err + } + + if l.Name != "" && l.Name != subst.Name { + // not the substitution that was requested by list + return nil + } + + l.Substitutions = append(l.Substitutions, subst) + return nil + }) + if err != nil { + return err + } + + // sort the substitutions by their name + sort.Slice(l.Substitutions, func(i, j int) bool { + return l.Substitutions[i].Name < l.Substitutions[j].Name + }) + + return nil +} + // count returns the number of fields set by the setter with name func (l *List) count(path, name string) (int, error) { s := &Set{Name: name} diff --git a/kyaml/setters2/list_test.go b/kyaml/setters2/list_test.go index 4b1a24874..291992060 100644 --- a/kyaml/setters2/list_test.go +++ b/kyaml/setters2/list_test.go @@ -276,7 +276,7 @@ spec: // invoke the setter instance := &List{Name: test.setter} - err = instance.List(f.Name(), r.Name()) + err = instance.ListSetters(f.Name(), r.Name()) if !assert.NoError(t, err) { t.FailNow() }