mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 17:12:51 +00:00
wire set 2.0 command
This commit is contained in:
@@ -6,19 +6,21 @@ package commands
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/olekukonko/tablewriter"
|
"github.com/olekukonko/tablewriter"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
"sigs.k8s.io/kustomize/kyaml/setters"
|
"sigs.k8s.io/kustomize/kyaml/setters"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewSetRunner returns a command runner.
|
// NewSetRunner returns a command runner.
|
||||||
func NewSetRunner(parent string) *SetRunner {
|
func NewSetRunner(parent string) *SetRunner {
|
||||||
r := &SetRunner{}
|
r := &SetRunner{}
|
||||||
c := &cobra.Command{
|
c := &cobra.Command{
|
||||||
Use: "set DIR [NAME] [VALUE]",
|
Use: "set DIR NAME [VALUE]",
|
||||||
Args: cobra.RangeArgs(1, 3),
|
Args: cobra.RangeArgs(1, 3),
|
||||||
Short: commands.SetShort,
|
Short: commands.SetShort,
|
||||||
Long: commands.SetLong,
|
Long: commands.SetLong,
|
||||||
@@ -32,18 +34,48 @@ func NewSetRunner(parent string) *SetRunner {
|
|||||||
"annotate the field with who set it")
|
"annotate the field with who set it")
|
||||||
c.Flags().StringVar(&r.Perform.Description, "description", "",
|
c.Flags().StringVar(&r.Perform.Description, "description", "",
|
||||||
"annotate the field with a description of its value")
|
"annotate the field with a description of its value")
|
||||||
|
c.Flags().StringVar(&setterVersion, "version", "",
|
||||||
|
"use this version of the setter format")
|
||||||
|
c.Flags().MarkHidden("version")
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var setterVersion string
|
||||||
|
|
||||||
|
var GetOpenAPIFile = func(args []string) (string, error) {
|
||||||
|
return filepath.Join(args[0], "kustomization"), nil
|
||||||
|
}
|
||||||
|
|
||||||
func SetCommand(parent string) *cobra.Command {
|
func SetCommand(parent string) *cobra.Command {
|
||||||
return NewSetRunner(parent).Command
|
return NewSetRunner(parent).Command
|
||||||
}
|
}
|
||||||
|
|
||||||
type SetRunner struct {
|
type SetRunner struct {
|
||||||
Command *cobra.Command
|
Command *cobra.Command
|
||||||
Lookup setters.LookupSetters
|
Lookup setters.LookupSetters
|
||||||
Perform setters.PerformSetters
|
Perform setters.PerformSetters
|
||||||
|
Set settersutil.FieldSetter
|
||||||
|
OpenAPIFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
func initSetterVersion(c *cobra.Command, args []string) error {
|
||||||
|
setterVersion = "v2"
|
||||||
|
l := setters.LookupSetters{}
|
||||||
|
|
||||||
|
// backwards compatibility for resources with setter v1
|
||||||
|
err := kio.Pipeline{
|
||||||
|
Inputs: []kio.Reader{&kio.LocalPackageReader{PackagePath: args[0]}},
|
||||||
|
Filters: []kio.Filter{&l},
|
||||||
|
}.Execute()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(l.SetterCounts) > 0 {
|
||||||
|
setterVersion = "v1"
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *SetRunner) preRunE(c *cobra.Command, args []string) error {
|
func (r *SetRunner) preRunE(c *cobra.Command, args []string) error {
|
||||||
@@ -55,15 +87,37 @@ func (r *SetRunner) preRunE(c *cobra.Command, args []string) error {
|
|||||||
r.Perform.Value = args[2]
|
r.Perform.Value = args[2]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if setterVersion == "" {
|
||||||
|
if len(args) < 3 {
|
||||||
|
setterVersion = "v1"
|
||||||
|
} else if err := initSetterVersion(c, args); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if setterVersion == "v2" {
|
||||||
|
var err error
|
||||||
|
r.Set.Name = args[1]
|
||||||
|
r.Set.Value = args[2]
|
||||||
|
r.Set.Description = r.Perform.Description
|
||||||
|
r.Set.SetBy = r.Perform.SetBy
|
||||||
|
r.OpenAPIFile, err = GetOpenAPIFile(args)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *SetRunner) runE(c *cobra.Command, args []string) error {
|
func (r *SetRunner) runE(c *cobra.Command, args []string) error {
|
||||||
|
if setterVersion == "v2" {
|
||||||
|
count, err := r.Set.Set(r.OpenAPIFile, args[0])
|
||||||
|
fmt.Fprintf(c.OutOrStdout(), "set %d fields\n", count)
|
||||||
|
return handleError(c, err)
|
||||||
|
}
|
||||||
if len(args) == 3 {
|
if len(args) == 3 {
|
||||||
return handleError(c, r.perform(c, args))
|
return handleError(c, r.perform(c, args))
|
||||||
}
|
}
|
||||||
|
|
||||||
return handleError(c, lookup(r.Lookup, c, args))
|
return handleError(c, lookup(r.Lookup, c, args))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
275
cmd/config/internal/commands/cmdset_test.go
Normal file
275
cmd/config/internal/commands/cmdset_test.go
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package commands_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSetCommand(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
name string
|
||||||
|
inputOpenAPI string
|
||||||
|
input string
|
||||||
|
args []string
|
||||||
|
out string
|
||||||
|
expectedOpenAPI string
|
||||||
|
expectedResources string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "set replicas",
|
||||||
|
args: []string{"replicas", "4", "--description", "hi there", "--set-by", "pw"},
|
||||||
|
out: "set 1 fields\n",
|
||||||
|
inputOpenAPI: `
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: Example
|
||||||
|
openAPI:
|
||||||
|
definitions:
|
||||||
|
io.k8s.cli.setters.replicas:
|
||||||
|
description: hello world
|
||||||
|
x-k8s-cli:
|
||||||
|
setter:
|
||||||
|
name: replicas
|
||||||
|
value: "3"
|
||||||
|
setBy: me
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx-deployment
|
||||||
|
spec:
|
||||||
|
replicas: 3 # {"$ref":"#/definitions/io.k8s.cli.setters.replicas"}
|
||||||
|
`,
|
||||||
|
expectedOpenAPI: `
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: Example
|
||||||
|
openAPI:
|
||||||
|
definitions:
|
||||||
|
io.k8s.cli.setters.replicas:
|
||||||
|
description: hi there
|
||||||
|
x-k8s-cli:
|
||||||
|
setter:
|
||||||
|
name: replicas
|
||||||
|
value: "4"
|
||||||
|
setBy: pw
|
||||||
|
`,
|
||||||
|
expectedResources: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx-deployment
|
||||||
|
spec:
|
||||||
|
replicas: 4 # {"$ref":"#/definitions/io.k8s.cli.setters.replicas"}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "set replicas no description",
|
||||||
|
args: []string{"replicas", "4"},
|
||||||
|
out: "set 1 fields\n",
|
||||||
|
inputOpenAPI: `
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: Example
|
||||||
|
openAPI:
|
||||||
|
definitions:
|
||||||
|
io.k8s.cli.setters.replicas:
|
||||||
|
description: hello world
|
||||||
|
x-k8s-cli:
|
||||||
|
setter:
|
||||||
|
name: replicas
|
||||||
|
value: "3"
|
||||||
|
setBy: me
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx-deployment
|
||||||
|
spec:
|
||||||
|
replicas: 3 # {"$ref":"#/definitions/io.k8s.cli.setters.replicas"}
|
||||||
|
`,
|
||||||
|
expectedOpenAPI: `
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: Example
|
||||||
|
openAPI:
|
||||||
|
definitions:
|
||||||
|
io.k8s.cli.setters.replicas:
|
||||||
|
description: hello world
|
||||||
|
x-k8s-cli:
|
||||||
|
setter:
|
||||||
|
name: replicas
|
||||||
|
value: "4"
|
||||||
|
setBy: me
|
||||||
|
`,
|
||||||
|
expectedResources: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx-deployment
|
||||||
|
spec:
|
||||||
|
replicas: 4 # {"$ref":"#/definitions/io.k8s.cli.setters.replicas"}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "set image",
|
||||||
|
args: []string{"tag", "1.8.1"},
|
||||||
|
out: "set 1 fields\n",
|
||||||
|
inputOpenAPI: `
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: Example
|
||||||
|
openAPI:
|
||||||
|
definitions:
|
||||||
|
io.k8s.cli.setters.image:
|
||||||
|
x-k8s-cli:
|
||||||
|
setter:
|
||||||
|
name: image
|
||||||
|
value: "nginx"
|
||||||
|
io.k8s.cli.setters.tag:
|
||||||
|
x-k8s-cli:
|
||||||
|
setter:
|
||||||
|
name: tag
|
||||||
|
value: "1.7.9"
|
||||||
|
io.k8s.cli.substitutions.image:
|
||||||
|
x-k8s-cli:
|
||||||
|
substitution:
|
||||||
|
name: image
|
||||||
|
pattern: IMAGE:TAG
|
||||||
|
values:
|
||||||
|
- marker: IMAGE
|
||||||
|
ref: '#/definitions/io.k8s.cli.setters.image'
|
||||||
|
- marker: TAG
|
||||||
|
ref: '#/definitions/io.k8s.cli.setters.tag'
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx-deployment
|
||||||
|
spec:
|
||||||
|
replicas: 3
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx:1.7.9 # {"$ref":"#/definitions/io.k8s.cli.substitutions.image"}
|
||||||
|
- name: sidecar
|
||||||
|
image: sidecar:1.7.9
|
||||||
|
`,
|
||||||
|
expectedOpenAPI: `
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: Example
|
||||||
|
openAPI:
|
||||||
|
definitions:
|
||||||
|
io.k8s.cli.setters.image:
|
||||||
|
x-k8s-cli:
|
||||||
|
setter:
|
||||||
|
name: image
|
||||||
|
value: "nginx"
|
||||||
|
io.k8s.cli.setters.tag:
|
||||||
|
x-k8s-cli:
|
||||||
|
setter:
|
||||||
|
name: tag
|
||||||
|
value: "1.8.1"
|
||||||
|
io.k8s.cli.substitutions.image:
|
||||||
|
x-k8s-cli:
|
||||||
|
substitution:
|
||||||
|
name: image
|
||||||
|
pattern: IMAGE:TAG
|
||||||
|
values:
|
||||||
|
- marker: IMAGE
|
||||||
|
ref: '#/definitions/io.k8s.cli.setters.image'
|
||||||
|
- marker: TAG
|
||||||
|
ref: '#/definitions/io.k8s.cli.setters.tag'
|
||||||
|
|
||||||
|
`,
|
||||||
|
expectedResources: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx-deployment
|
||||||
|
spec:
|
||||||
|
replicas: 3
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx:1.8.1 # {"$ref":"#/definitions/io.k8s.cli.substitutions.image"}
|
||||||
|
- name: sidecar
|
||||||
|
image: sidecar:1.7.9
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i := range tests {
|
||||||
|
test := tests[i]
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
// reset the openAPI afterward
|
||||||
|
openapi.ResetOpenAPI()
|
||||||
|
defer openapi.ResetOpenAPI()
|
||||||
|
|
||||||
|
f, err := ioutil.TempFile("", "k8s-cli-")
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
defer os.Remove(f.Name())
|
||||||
|
err = ioutil.WriteFile(f.Name(), []byte(test.inputOpenAPI), 0600)
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
commands.GetOpenAPIFile = func(args []string) (s string, err error) {
|
||||||
|
return f.Name(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := ioutil.TempFile("", "k8s-cli-*.yaml")
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
defer os.Remove(r.Name())
|
||||||
|
err = ioutil.WriteFile(r.Name(), []byte(test.input), 0600)
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
runner := commands.NewSetRunner("")
|
||||||
|
out := &bytes.Buffer{}
|
||||||
|
runner.Command.SetOut(out)
|
||||||
|
runner.Command.SetArgs(append([]string{r.Name()}, test.args...))
|
||||||
|
err = runner.Command.Execute()
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assert.Equal(t, test.out, out.String()) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
actualResources, err := ioutil.ReadFile(r.Name())
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if !assert.Equal(t,
|
||||||
|
strings.TrimSpace(test.expectedResources),
|
||||||
|
strings.TrimSpace(string(actualResources))) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
actualOpenAPI, err := ioutil.ReadFile(f.Name())
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if !assert.Equal(t,
|
||||||
|
strings.TrimSpace(test.expectedOpenAPI),
|
||||||
|
strings.TrimSpace(string(actualOpenAPI))) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -125,6 +125,10 @@ type SetOpenAPI struct {
|
|||||||
Name string `yaml:"name"`
|
Name string `yaml:"name"`
|
||||||
// Value is the current value of the setter
|
// Value is the current value of the setter
|
||||||
Value string `yaml:"value"`
|
Value string `yaml:"value"`
|
||||||
|
|
||||||
|
Description string `yaml:"description"`
|
||||||
|
|
||||||
|
SetBy string `yaml:"setBy"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateFile updates the OpenAPI definitions in a file with the given setter value.
|
// UpdateFile updates the OpenAPI definitions in a file with the given setter value.
|
||||||
@@ -146,5 +150,22 @@ func (s SetOpenAPI) Filter(object *yaml.RNode) (*yaml.RNode, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.SetBy != "" {
|
||||||
|
if err := def.PipeE(&yaml.FieldSetter{Name: "setBy", StringValue: s.SetBy}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Description != "" {
|
||||||
|
d, err := object.Pipe(yaml.LookupCreate(
|
||||||
|
yaml.MappingNode, "openAPI", "definitions", key))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := d.PipeE(&yaml.FieldSetter{Name: "description", StringValue: s.Description}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return object, nil
|
return object, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,17 @@ type FieldSetter struct {
|
|||||||
|
|
||||||
// Value is the value to set
|
// Value is the value to set
|
||||||
Value string
|
Value string
|
||||||
|
|
||||||
|
Description string
|
||||||
|
|
||||||
|
SetBy string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set updates the OpenAPI definitions and resources with the new setter value
|
// Set updates the OpenAPI definitions and resources with the new setter value
|
||||||
func (fs FieldSetter) Set(openAPIPath, resourcesPath string) (int, error) {
|
func (fs FieldSetter) Set(openAPIPath, resourcesPath string) (int, error) {
|
||||||
// Update the OpenAPI definitions
|
// Update the OpenAPI definitions
|
||||||
soa := setters2.SetOpenAPI{Name: fs.Name, Value: fs.Value}
|
soa := setters2.SetOpenAPI{
|
||||||
|
Name: fs.Name, Value: fs.Value, Description: fs.Description, SetBy: fs.SetBy}
|
||||||
if err := soa.UpdateFile(openAPIPath); err != nil {
|
if err := soa.UpdateFile(openAPIPath); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user