mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
kyaml: refactor command documentation into .md files from go files
No new documentation added.
This commit is contained in:
@@ -8,7 +8,7 @@ GOBIN := $(shell go env GOPATH)/bin
|
||||
build:
|
||||
go build -v -o $(GOBIN)/config .
|
||||
|
||||
all: generate license fix vet fmt test lint tidy
|
||||
all: generate build license fix vet fmt test lint tidy
|
||||
|
||||
fix:
|
||||
go fix ./...
|
||||
@@ -17,6 +17,7 @@ fmt:
|
||||
go fmt ./...
|
||||
|
||||
generate:
|
||||
(which $(GOBIN)/mdtogo || go get sigs.k8s.io/kustomize/cmd/mdtogo)
|
||||
GOBIN=$(GOBIN) go generate ./...
|
||||
|
||||
license:
|
||||
|
||||
@@ -1,4 +1,21 @@
|
||||
# cmd/config
|
||||
|
||||
This package exists to expose kyaml filters directly as cli commands for the purposes
|
||||
This package exists to expose config filters directly as cli commands for the purposes
|
||||
of development of the kyaml package and as a reference implementation for using the libraries.
|
||||
|
||||
## Docs:
|
||||
|
||||
- [commands](docs/commands)
|
||||
- [api-conventions](docs/api-conventions)
|
||||
|
||||
## Build Command
|
||||
|
||||
Build the `config` command under `GOBIN`
|
||||
|
||||
$ make
|
||||
|
||||
## Run Tests
|
||||
|
||||
Run all tests, linting, etc and build
|
||||
|
||||
$ make all
|
||||
@@ -7,33 +7,23 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/cmddocs/commands"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// GetCatRunner returns a command CatRunner.
|
||||
func GetCatRunner() *CatRunner {
|
||||
func GetCatRunner(name string) *CatRunner {
|
||||
r := &CatRunner{}
|
||||
c := &cobra.Command{
|
||||
Use: "cat DIR...",
|
||||
Short: "Print Resource Config from a local directory",
|
||||
Long: `Print Resource Config from a local directory.
|
||||
|
||||
DIR:
|
||||
Path to local directory.
|
||||
`,
|
||||
Example: `# print Resource config from a directory
|
||||
kyaml cat my-dir/
|
||||
|
||||
# wrap Resource config from a directory in an ResourceList
|
||||
kyaml cat my-dir/ --wrap-kind ResourceList --wrap-version config.kubernetes.io/v1alpha1 --function-config fn.yaml
|
||||
|
||||
# unwrap Resource config from a directory in an ResourceList
|
||||
... | kyaml cat
|
||||
`,
|
||||
RunE: r.runE,
|
||||
Use: "cat DIR...",
|
||||
Short: commands.CatShort,
|
||||
Long: commands.CatLong,
|
||||
Example: commands.CatExamples,
|
||||
RunE: r.runE,
|
||||
}
|
||||
fixDocs(name, c)
|
||||
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
|
||||
"also print resources from subpackages.")
|
||||
c.Flags().BoolVar(&r.Format, "format", true,
|
||||
@@ -59,8 +49,8 @@ kyaml cat my-dir/ --wrap-kind ResourceList --wrap-version config.kubernetes.io/v
|
||||
return r
|
||||
}
|
||||
|
||||
func CatCommand() *cobra.Command {
|
||||
return GetCatRunner().Command
|
||||
func CatCommand(name string) *cobra.Command {
|
||||
return GetCatRunner(name).Command
|
||||
}
|
||||
|
||||
// CatRunner contains the run function
|
||||
|
||||
@@ -76,7 +76,7 @@ spec:
|
||||
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetCatRunner()
|
||||
r := cmd.GetCatRunner("")
|
||||
r.Command.SetArgs([]string{d})
|
||||
r.Command.SetOut(b)
|
||||
if !assert.NoError(t, r.Command.Execute()) {
|
||||
@@ -182,7 +182,7 @@ spec:
|
||||
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetCatRunner()
|
||||
r := cmd.GetCatRunner("")
|
||||
r.Command.SetArgs([]string{d, "--include-local"})
|
||||
r.Command.SetOut(b)
|
||||
if !assert.NoError(t, r.Command.Execute()) {
|
||||
@@ -301,7 +301,7 @@ spec:
|
||||
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetCatRunner()
|
||||
r := cmd.GetCatRunner("")
|
||||
r.Command.SetArgs([]string{d, "--include-local", "--exclude-non-local"})
|
||||
r.Command.SetOut(b)
|
||||
if !assert.NoError(t, r.Command.Execute()) {
|
||||
|
||||
@@ -8,26 +8,22 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/cmddocs/commands"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/sets"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
func GetCountRunner() *CountRunner {
|
||||
func GetCountRunner(name string) *CountRunner {
|
||||
r := &CountRunner{}
|
||||
c := &cobra.Command{
|
||||
Use: "count DIR...",
|
||||
Short: "Count Resources Config from a local directory",
|
||||
Long: `Count Resources Config from a local directory.
|
||||
|
||||
DIR:
|
||||
Path to local directory.
|
||||
`,
|
||||
Example: `# print Resource counts from a directory
|
||||
kyaml count my-dir/
|
||||
`,
|
||||
RunE: r.runE,
|
||||
Use: "count DIR...",
|
||||
Short: commands.CountShort,
|
||||
Long: commands.CountLong,
|
||||
Example: commands.CountExamples,
|
||||
RunE: r.runE,
|
||||
}
|
||||
fixDocs(name, c)
|
||||
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
|
||||
"also print resources from subpackages.")
|
||||
c.Flags().BoolVar(&r.Kind, "kind", true,
|
||||
@@ -37,8 +33,8 @@ kyaml count my-dir/
|
||||
return r
|
||||
}
|
||||
|
||||
func CountCommand() *cobra.Command {
|
||||
return GetCountRunner().Command
|
||||
func CountCommand(name string) *cobra.Command {
|
||||
return GetCountRunner(name).Command
|
||||
}
|
||||
|
||||
// CountRunner contains the run function
|
||||
|
||||
@@ -60,7 +60,7 @@ spec:
|
||||
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetCountRunner()
|
||||
r := cmd.GetCountRunner("")
|
||||
r.Command.SetArgs([]string{d})
|
||||
r.Command.SetOut(b)
|
||||
if !assert.NoError(t, r.Command.Execute()) {
|
||||
|
||||
@@ -5,57 +5,23 @@ package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/cmddocs/commands"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
)
|
||||
|
||||
// FmtCmd returns a command FmtRunner.
|
||||
func GetFmtRunner() *FmtRunner {
|
||||
func GetFmtRunner(name string) *FmtRunner {
|
||||
r := &FmtRunner{}
|
||||
c := &cobra.Command{
|
||||
Use: "fmt",
|
||||
Short: "Format yaml configuration files",
|
||||
Long: `Format yaml configuration files
|
||||
|
||||
Fmt will format input by ordering fields and unordered list items in Kubernetes
|
||||
objects. Inputs may be directories, files or stdin, and their contents must
|
||||
include both apiVersion and kind fields.
|
||||
|
||||
- Stdin inputs are formatted and written to stdout
|
||||
- File inputs (args) are formatted and written back to the file
|
||||
- Directory inputs (args) are walked, each encountered .yaml and .yml file
|
||||
acts as an input
|
||||
|
||||
For inputs which contain multiple yaml documents separated by \n---\n,
|
||||
each document will be formatted and written back to the file in the original
|
||||
order.
|
||||
|
||||
Field ordering roughly follows the ordering defined in the source Kubernetes
|
||||
resource definitions (i.e. go structures), falling back on lexicographical
|
||||
sorting for unrecognized fields.
|
||||
|
||||
Unordered list item ordering is defined for specific Resource types and
|
||||
field paths.
|
||||
|
||||
- .spec.template.spec.containers (by element name)
|
||||
- .webhooks.rules.operations (by element value)
|
||||
`,
|
||||
Example: `
|
||||
# format file1.yaml and file2.yml
|
||||
kyaml fmt file1.yaml file2.yml
|
||||
|
||||
# format all *.yaml and *.yml recursively traversing directories
|
||||
kyaml fmt my-dir/
|
||||
|
||||
# format kubectl output
|
||||
kubectl get -o yaml deployments | kyaml fmt
|
||||
|
||||
# format kustomize output
|
||||
kustomize build | kyaml fmt
|
||||
`,
|
||||
Use: "fmt",
|
||||
Short: commands.FmtShort,
|
||||
Long: commands.FmtLong,
|
||||
Example: commands.FmtExamples,
|
||||
RunE: r.runE,
|
||||
PreRunE: r.preRunE,
|
||||
}
|
||||
fixDocs(name, c)
|
||||
c.Flags().StringVar(&r.FilenamePattern, "pattern", filters.DefaultFilenamePattern,
|
||||
`pattern to use for generating filenames for resources -- may contain the following
|
||||
formatting substitution verbs {'%n': 'metadata.name', '%s': 'metadata.namespace', '%k': 'kind'}`)
|
||||
@@ -69,8 +35,8 @@ formatting substitution verbs {'%n': 'metadata.name', '%s': 'metadata.namespace'
|
||||
return r
|
||||
}
|
||||
|
||||
func FmtCommand() *cobra.Command {
|
||||
return GetFmtRunner().Command
|
||||
func FmtCommand(name string) *cobra.Command {
|
||||
return GetFmtRunner(name).Command
|
||||
}
|
||||
|
||||
// FmtRunner contains the run function
|
||||
|
||||
@@ -38,7 +38,7 @@ func TestFmtCommand_files(t *testing.T) {
|
||||
}
|
||||
|
||||
// fmt the files
|
||||
r := cmd.GetFmtRunner()
|
||||
r := cmd.GetFmtRunner("")
|
||||
r.Command.SetArgs([]string{f1.Name(), f2.Name()})
|
||||
err = r.Command.Execute()
|
||||
if !assert.NoError(t, err) {
|
||||
@@ -65,7 +65,7 @@ func TestFmtCommand_files(t *testing.T) {
|
||||
|
||||
func TestFmtCommand_stdin(t *testing.T) {
|
||||
out := &bytes.Buffer{}
|
||||
r := cmd.GetFmtRunner()
|
||||
r := cmd.GetFmtRunner("")
|
||||
r.Command.SetOut(out)
|
||||
r.Command.SetIn(bytes.NewReader(testyaml.UnformattedYaml1))
|
||||
|
||||
@@ -100,12 +100,12 @@ func TestFmtCmd_filesAndStdin(t *testing.T) {
|
||||
|
||||
out := &bytes.Buffer{}
|
||||
in := &bytes.Buffer{}
|
||||
r := cmd.GetFmtRunner()
|
||||
r := cmd.GetFmtRunner("")
|
||||
r.Command.SetOut(out)
|
||||
r.Command.SetIn(in)
|
||||
|
||||
// fmt the files
|
||||
r = cmd.GetFmtRunner()
|
||||
r = cmd.GetFmtRunner("")
|
||||
r.Command.SetArgs([]string{f1.Name(), f2.Name()})
|
||||
err = r.Command.Execute()
|
||||
if !assert.NoError(t, err) {
|
||||
@@ -141,7 +141,7 @@ func TestFmtCmd_filesAndStdin(t *testing.T) {
|
||||
// TestCmd_files verifies the fmt command formats the files
|
||||
func TestCmd_failFiles(t *testing.T) {
|
||||
// fmt the files
|
||||
r := cmd.GetFmtRunner()
|
||||
r := cmd.GetFmtRunner("")
|
||||
r.Command.SetArgs([]string{"notrealfile"})
|
||||
err := r.Command.Execute()
|
||||
assert.EqualError(t, err, "lstat notrealfile: no such file or directory")
|
||||
@@ -150,7 +150,7 @@ func TestCmd_failFiles(t *testing.T) {
|
||||
// TestCmd_files verifies the fmt command formats the files
|
||||
func TestCmd_failFileContents(t *testing.T) {
|
||||
out := &bytes.Buffer{}
|
||||
r := cmd.GetFmtRunner()
|
||||
r := cmd.GetFmtRunner("")
|
||||
r.Command.SetOut(out)
|
||||
r.Command.SetIn(strings.NewReader(`{`))
|
||||
|
||||
|
||||
@@ -8,44 +8,25 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/cmddocs/commands"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/api/resource"
|
||||
)
|
||||
|
||||
// Cmd returns a command GrepRunner.
|
||||
func GetGrepRunner() *GrepRunner {
|
||||
func GetGrepRunner(name string) *GrepRunner {
|
||||
r := &GrepRunner{}
|
||||
c := &cobra.Command{
|
||||
Use: "grep QUERY [DIR]...",
|
||||
Short: "Search for matching Resources in a directory or from stdin",
|
||||
Long: `Search for matching Resources in a directory or from stdin.
|
||||
QUERY:
|
||||
Query to match expressed as 'path.to.field=value'.
|
||||
Maps and fields are matched as '.field-name' or '.map-key'
|
||||
List elements are matched as '[list-elem-field=field-value]'
|
||||
The value to match is expressed as '=value'
|
||||
'.' as part of a key or value can be escaped as '\.'
|
||||
|
||||
DIR:
|
||||
Path to local directory.
|
||||
`,
|
||||
Example: `# find Deployment Resources
|
||||
kyaml grep "kind=Deployment" my-dir/
|
||||
|
||||
# find Resources named nginx
|
||||
kyaml grep "metadata.name=nginx" my-dir/
|
||||
|
||||
# use tree to display matching Resources
|
||||
kyaml grep "metadata.name=nginx" my-dir/ | kyaml tree
|
||||
|
||||
# look for Resources matching a specific container image
|
||||
kyaml grep "spec.template.spec.containers[name=nginx].image=nginx:1\.7\.9" my-dir/ | kyaml tree
|
||||
`,
|
||||
Use: "grep QUERY [DIR]...",
|
||||
Short: commands.GrepShort,
|
||||
Long: commands.GrepLong,
|
||||
Example: commands.GrepExamples,
|
||||
PreRunE: r.preRunE,
|
||||
RunE: r.runE,
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
}
|
||||
fixDocs(name, c)
|
||||
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
|
||||
"also print resources from subpackages.")
|
||||
c.Flags().BoolVar(&r.KeepAnnotations, "annotate", true,
|
||||
@@ -57,8 +38,8 @@ kyaml grep "spec.template.spec.containers[name=nginx].image=nginx:1\.7\.9" my-di
|
||||
return r
|
||||
}
|
||||
|
||||
func GrepCommand() *cobra.Command {
|
||||
return GetGrepRunner().Command
|
||||
func GrepCommand(name string) *cobra.Command {
|
||||
return GetGrepRunner(name).Command
|
||||
}
|
||||
|
||||
// GrepRunner contains the run function
|
||||
|
||||
@@ -61,7 +61,7 @@ spec:
|
||||
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetGrepRunner()
|
||||
r := cmd.GetGrepRunner("")
|
||||
r.Command.SetArgs([]string{"metadata.name=foo", d})
|
||||
r.Command.SetOut(b)
|
||||
if !assert.NoError(t, r.Command.Execute()) {
|
||||
@@ -101,7 +101,7 @@ spec:
|
||||
func TestGrepCmd_stdin(t *testing.T) {
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetGrepRunner()
|
||||
r := cmd.GetGrepRunner("")
|
||||
r.Command.SetArgs([]string{"metadata.name=foo"})
|
||||
r.Command.SetOut(b)
|
||||
r.Command.SetIn(bytes.NewBufferString(`
|
||||
@@ -166,7 +166,7 @@ spec:
|
||||
// TestGrepCmd_errInputs verifies the grep command errors on invalid matches
|
||||
func TestGrepCmd_errInputs(t *testing.T) {
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetGrepRunner()
|
||||
r := cmd.GetGrepRunner("")
|
||||
r.Command.SetArgs([]string{"metadata.name=foo=bar"})
|
||||
r.Command.SetOut(b)
|
||||
r.Command.SetIn(bytes.NewBufferString(`
|
||||
@@ -188,7 +188,7 @@ spec:
|
||||
|
||||
// fmt the files
|
||||
b = &bytes.Buffer{}
|
||||
r = cmd.GetGrepRunner()
|
||||
r = cmd.GetGrepRunner("")
|
||||
r.Command.SetArgs([]string{"spec.template.spec.containers[a[b=c].image=foo"})
|
||||
r.Command.SetOut(b)
|
||||
r.Command.SetIn(bytes.NewBufferString(`
|
||||
@@ -213,7 +213,7 @@ spec:
|
||||
func TestGrepCommand_escapeDots(t *testing.T) {
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetGrepRunner()
|
||||
r := cmd.GetGrepRunner("")
|
||||
r.Command.SetArgs([]string{"spec.template.spec.containers[name=nginx].image=nginx:1\\.7\\.9",
|
||||
"--annotate=false"})
|
||||
r.Command.SetOut(b)
|
||||
|
||||
@@ -5,41 +5,29 @@ package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/cmddocs/commands"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
)
|
||||
|
||||
func GetMergeRunner() *MergeRunner {
|
||||
func GetMergeRunner(name string) *MergeRunner {
|
||||
r := &MergeRunner{}
|
||||
c := &cobra.Command{
|
||||
Use: "merge [SOURCE_DIR...] [DESTINATION_DIR]",
|
||||
Short: "Merge Resource configuration files",
|
||||
Long: `Merge Resource configuration files
|
||||
|
||||
Merge reads Kubernetes Resource yaml configuration files from stdin or sources packages and write
|
||||
the result to stdout or a destination package.
|
||||
|
||||
Resources are merged using the Resource [apiVersion, kind, name, namespace] as the key. If any of
|
||||
these are missing, merge will default the missing values to empty.
|
||||
|
||||
Resources specified later are high-precedence (the source) and Resources specified
|
||||
earlier are lower-precedence (the destination).
|
||||
|
||||
For information on merge rules, run:
|
||||
|
||||
kyaml help merge
|
||||
`,
|
||||
Example: `cat resources_and_patches.yaml | kyaml merge > merged_resources.yaml`,
|
||||
Use: "merge [SOURCE_DIR...] [DESTINATION_DIR]",
|
||||
Short: commands.MergeShort,
|
||||
Long: commands.MergeLong,
|
||||
Example: commands.MergeExamples,
|
||||
RunE: r.runE,
|
||||
}
|
||||
fixDocs(name, c)
|
||||
r.Command = c
|
||||
r.Command.Flags().BoolVar(&r.InvertOrder, "invert-order", false,
|
||||
"if true, merge Resources in the reverse order")
|
||||
return r
|
||||
}
|
||||
|
||||
func MergeCommand() *cobra.Command {
|
||||
return GetMergeRunner().Command
|
||||
func MergeCommand(name string) *cobra.Command {
|
||||
return GetMergeRunner(name).Command
|
||||
}
|
||||
|
||||
// MergeRunner contains the run function
|
||||
|
||||
@@ -5,64 +5,22 @@ package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/cmddocs/commands"
|
||||
"sigs.k8s.io/kustomize/kyaml/runfn"
|
||||
)
|
||||
|
||||
// GetCatRunner returns a RunFnRunner.
|
||||
func GetRunFnRunner() *RunFnRunner {
|
||||
func GetRunFnRunner(name string) *RunFnRunner {
|
||||
r := &RunFnRunner{}
|
||||
c := &cobra.Command{
|
||||
Use: "run-fns DIR",
|
||||
Short: "Apply config functions to Resources.",
|
||||
Long: `Apply config functions to Resources.
|
||||
|
||||
run-fns sequentially invokes all config functions in the directly, providing Resources
|
||||
in the directory as input to the first function, and writing the output of the last
|
||||
function back to the directory.
|
||||
|
||||
The ordering of functions is determined by the order they are encountered when walking the
|
||||
directory. To clearly specify an ordering of functions, multiple functions may be
|
||||
declared in the same file, separated by '---' (the functions will be invoked in the
|
||||
order they appear in the file).
|
||||
|
||||
### Arguments:
|
||||
|
||||
DIR:
|
||||
Path to local directory.
|
||||
|
||||
|
||||
### Config Functions:
|
||||
|
||||
Config functions are specified as Kubernetes types containing a metadata.configFn.container.image
|
||||
field. This fields tells run-fns how to invoke the container.
|
||||
|
||||
Example config function:
|
||||
|
||||
# in file example/fn.yaml
|
||||
apiVersion: fn.example.com/v1beta1
|
||||
kind: ExampleFunctionKind
|
||||
metadata:
|
||||
configFn:
|
||||
container:
|
||||
# function is invoked as a container running this image
|
||||
image: gcr.io/example/examplefunction:v1.0.1
|
||||
annotations:
|
||||
config.kubernetes.io/local-config: "true" # tools should ignore this
|
||||
spec:
|
||||
configField: configValue
|
||||
|
||||
In the preceding example, 'kyaml run-fns example/' would identify the function by
|
||||
the metadata.configFn field. It would then write all Resources in the directory to
|
||||
a container stdin (running the gcr.io/example/examplefunction:v1.0.1 image). It
|
||||
would then writer the container stdout back to example/, replacing the directory
|
||||
file contents.
|
||||
`,
|
||||
Example: `
|
||||
kyaml run-fns example/
|
||||
`,
|
||||
RunE: r.runE,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Use: "run-fns DIR",
|
||||
Short: commands.RunFnsShort,
|
||||
Long: commands.RunFnsLong,
|
||||
Example: commands.RunFnsExamples,
|
||||
RunE: r.runE,
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
fixDocs(name, c)
|
||||
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
|
||||
"also print resources from subpackages.")
|
||||
r.Command = c
|
||||
@@ -76,8 +34,8 @@ kyaml run-fns example/
|
||||
return r
|
||||
}
|
||||
|
||||
func RunFnCommand() *cobra.Command {
|
||||
return GetRunFnRunner().Command
|
||||
func RunFnCommand(name string) *cobra.Command {
|
||||
return GetRunFnRunner(name).Command
|
||||
}
|
||||
|
||||
// RunFnRunner contains the run function
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/cmd/config/cmddocs/commands"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
@@ -14,61 +15,17 @@ import (
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
func GetTreeRunner() *TreeRunner {
|
||||
func GetTreeRunner(name string) *TreeRunner {
|
||||
r := &TreeRunner{}
|
||||
c := &cobra.Command{
|
||||
Use: "tree DIR",
|
||||
Short: "Display Resource structure from a directory or stdin",
|
||||
Long: `Display Resource structure from a directory or stdin.
|
||||
|
||||
kyaml tree may be used to print Resources in a directory or cluster, preserving structure
|
||||
|
||||
Args:
|
||||
|
||||
DIR:
|
||||
Path to local directory directory.
|
||||
|
||||
Resource fields may be printed as part of the Resources by specifying the fields as flags.
|
||||
|
||||
kyaml tree has build-in support for printing common fields, such as replicas, container images,
|
||||
container names, etc.
|
||||
|
||||
kyaml tree supports printing arbitrary fields using the '--field' flag.
|
||||
|
||||
By default, kyaml tree uses the directory structure for the tree structure, however when printing
|
||||
from the cluster, the Resource graph structure may be used instead.
|
||||
`,
|
||||
Example: `# print Resources using directory structure
|
||||
kyaml tree my-dir/
|
||||
|
||||
# print replicas, container name, and container image and fields for Resources
|
||||
kyaml tree my-dir --replicas --image --name
|
||||
|
||||
# print all common Resource fields
|
||||
kyaml tree my-dir/ --all
|
||||
|
||||
# print the "foo"" annotation
|
||||
kyaml tree my-dir/ --field "metadata.annotations.foo"
|
||||
|
||||
# print the "foo"" annotation
|
||||
kubectl get all -o yaml | kyaml tree my-dir/ --structure=graph \
|
||||
--field="status.conditions[type=Completed].status"
|
||||
|
||||
# print live Resources from a cluster using graph for structure
|
||||
kubectl get all -o yaml | kyaml tree --replicas --name --image --structure=graph
|
||||
|
||||
|
||||
# print live Resources using graph for structure
|
||||
kubectl get all,applications,releasetracks -o yaml | kyaml tree --structure=graph \
|
||||
--name --image --replicas \
|
||||
--field="status.conditions[type=Completed].status" \
|
||||
--field="status.conditions[type=Complete].status" \
|
||||
--field="status.conditions[type=Ready].status" \
|
||||
--field="status.conditions[type=ContainersReady].status"
|
||||
`,
|
||||
RunE: r.runE,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Use: "tree DIR",
|
||||
Short: commands.TreeShort,
|
||||
Long: commands.TreeLong,
|
||||
Example: commands.TreeExamples,
|
||||
RunE: r.runE,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
}
|
||||
fixDocs(name, c)
|
||||
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
|
||||
"also print resources from subpackages.")
|
||||
|
||||
@@ -95,8 +52,8 @@ kubectl get all,applications,releasetracks -o yaml | kyaml tree --structure=grap
|
||||
return r
|
||||
}
|
||||
|
||||
func TreeCommand() *cobra.Command {
|
||||
return GetTreeRunner().Command
|
||||
func TreeCommand(name string) *cobra.Command {
|
||||
return GetTreeRunner(name).Command
|
||||
}
|
||||
|
||||
// TreeRunner contains the run function
|
||||
|
||||
@@ -74,7 +74,7 @@ spec:
|
||||
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetTreeRunner()
|
||||
r := cmd.GetTreeRunner("")
|
||||
r.Command.SetArgs([]string{d})
|
||||
r.Command.SetOut(b)
|
||||
if !assert.NoError(t, r.Command.Execute()) {
|
||||
@@ -93,7 +93,7 @@ spec:
|
||||
func TestTreeCommand_stdin(t *testing.T) {
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetTreeRunner()
|
||||
r := cmd.GetTreeRunner("")
|
||||
r.Command.SetArgs([]string{})
|
||||
r.Command.SetIn(bytes.NewBufferString(`apiVersion: extensions/v1
|
||||
kind: Deployment
|
||||
@@ -263,7 +263,7 @@ spec:
|
||||
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetTreeRunner()
|
||||
r := cmd.GetTreeRunner("")
|
||||
r.Command.SetArgs([]string{d, "--include-local"})
|
||||
r.Command.SetOut(b)
|
||||
if !assert.NoError(t, r.Command.Execute()) {
|
||||
@@ -340,7 +340,7 @@ spec:
|
||||
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetTreeRunner()
|
||||
r := cmd.GetTreeRunner("")
|
||||
r.Command.SetArgs([]string{d, "--include-local", "--exclude-non-local"})
|
||||
r.Command.SetOut(b)
|
||||
if !assert.NoError(t, r.Command.Execute()) {
|
||||
|
||||
@@ -62,3 +62,13 @@ var ExitOnError bool
|
||||
|
||||
// StackOnError if true, will print a stack trace on failure.
|
||||
var StackOnError bool
|
||||
|
||||
const cmdName = "kyaml"
|
||||
|
||||
// FixDocs replaces instances of old with new in the docs for c
|
||||
func fixDocs(new string, c *cobra.Command) {
|
||||
c.Use = strings.ReplaceAll(c.Use, cmdName, new)
|
||||
c.Short = strings.ReplaceAll(c.Short, cmdName, new)
|
||||
c.Long = strings.ReplaceAll(c.Long, cmdName, new)
|
||||
c.Example = strings.ReplaceAll(c.Example, cmdName, new)
|
||||
}
|
||||
|
||||
144
cmd/config/cmddocs/api/docs.go
Normal file
144
cmd/config/cmddocs/api/docs.go
Normal file
@@ -0,0 +1,144 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by "mdtogo"; DO NOT EDIT.
|
||||
package api
|
||||
|
||||
var Merge2Long = `# Merge (2-way)
|
||||
|
||||
2-way merges fields from a source to a destination, overriding the destination fields
|
||||
where they differ.
|
||||
|
||||
### Merge Rules
|
||||
|
||||
Fields are recursively merged using the following rules:
|
||||
|
||||
- scalars
|
||||
- if present only in the dest, it keeps its value
|
||||
- if present in the src and is non-null, take the src value -- if ` + "`" + `null` + "`" + `, clear it
|
||||
- example src: ` + "`" + `5` + "`" + `, dest: ` + "`" + `3` + "`" + ` => result: ` + "`" + `5` + "`" + `
|
||||
|
||||
- non-associative lists -- lists without a merge key
|
||||
- if present only in the dest, it keeps its value
|
||||
- if present in the src and is non-null, take the src value -- if ` + "`" + `null` + "`" + `, clear it
|
||||
- example src: ` + "`" + `[1, 2, 3]` + "`" + `, dest: ` + "`" + `[a, b, c]` + "`" + ` => result: ` + "`" + `[1, 2, 3]` + "`" + `
|
||||
|
||||
- map keys and fields -- paired by the map-key / field-name
|
||||
- if present only in the dest, it keeps its value
|
||||
- if present only in the src, it is added to the dest
|
||||
- if the field is present in both the src and dest, and the src value is
|
||||
` + "`" + `null` + "`" + `, the field is removed from the dest
|
||||
- if the field is present in both the src and dest, the value is recursively merged
|
||||
- example src: ` + "`" + `{'key1': 'value1', 'key2': 'value2'}` + "`" + `,
|
||||
dest: ` + "`" + `{'key2': 'value0', 'key3': 'value3'}` + "`" + `
|
||||
=> result: ` + "`" + `{'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}` + "`" + `
|
||||
|
||||
- associative list elements -- paired by the associative key
|
||||
- if present only in the dest, it keeps its value in the list
|
||||
- if present only in the src, it is added to the dest list
|
||||
- if the field is present in both the src and dest, the value is recursively merged
|
||||
|
||||
### Associative Keys
|
||||
|
||||
Associative keys are used to identify "same" elements within 2 different lists, and merge them.
|
||||
The following fields are recognized as associative keys:
|
||||
|
||||
[` + "`" + `mountPath` + "`" + `, ` + "`" + `devicePath` + "`" + `, ` + "`" + `ip` + "`" + `, ` + "`" + `type` + "`" + `, ` + "`" + `topologyKey` + "`" + `, ` + "`" + `name` + "`" + `, ` + "`" + `containerPort` + "`" + `]
|
||||
|
||||
Any lists where all of the elements contain associative keys will be merged as associative lists.
|
||||
|
||||
### Example
|
||||
|
||||
> Source
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 3 # scalar
|
||||
template:
|
||||
spec:
|
||||
containers: # associative list -- (name)
|
||||
- name: nginx
|
||||
image: nginx:1.7
|
||||
command: ['new_run.sh', 'arg1'] # non-associative list
|
||||
- name: sidecar2
|
||||
image: sidecar2:v1
|
||||
|
||||
> Destination
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.6
|
||||
command: ['old_run.sh', 'arg0']
|
||||
- name: sidecar1
|
||||
image: sidecar1:v1
|
||||
|
||||
> Result
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 3 # scalar
|
||||
template:
|
||||
spec:
|
||||
containers: # associative list -- (name)
|
||||
- name: nginx
|
||||
image: nginx:1.7
|
||||
command: ['new_run.sh', 'arg1'] # non-associative list
|
||||
- name: sidecar1
|
||||
image: sidecar1:v1
|
||||
- name: sidecar2
|
||||
image: sidecar2:v1`
|
||||
|
||||
var Merge3Long = `# Merge (3-way)
|
||||
|
||||
3-way merge identifies changes between an original source + updated source and merges the result
|
||||
into a destination, overriding the destination fields where they have changed between
|
||||
original and updated.
|
||||
|
||||
### Resource MergeRules
|
||||
|
||||
- Resources present in the original and deleted from the update are deleted.
|
||||
- Resources missing from the original and added in the update are added.
|
||||
- Resources present only in the dest are kept without changes.
|
||||
- Resources present in both the update and the dest have their fields merged with the destination.
|
||||
|
||||
### Field Merge Rules
|
||||
|
||||
Fields are recursively merged using the following rules:
|
||||
|
||||
- scalars
|
||||
- if present in either dest or updated and ` + "`" + `null` + "`" + `, clear the value
|
||||
- if unchanged between original and updated, keep dest value
|
||||
- if changed between original and updated (added, deleted, changed), take the updated value
|
||||
|
||||
- non-associative lists -- lists without a merge key
|
||||
- if present in either dest or updated and ` + "`" + `null` + "`" + `, clear the value
|
||||
- if unchanged between original and updated, keep dest value
|
||||
- if changed between original and updated (added, deleted, changed), take the updated value
|
||||
|
||||
- map keys and fields -- paired by the map-key / field-name
|
||||
- if present in either dest or updated and ` + "`" + `null` + "`" + `, clear the value
|
||||
- if present only in the dest, it keeps its value
|
||||
- if not-present in the dest, add the delta between original-updated as a field
|
||||
- otherwise recursively merge the value between original, updated, dest
|
||||
|
||||
- associative list elements -- paired by the associative key
|
||||
- if present only in the dest, it keeps its value
|
||||
- if not-present in the dest, add the delta between original-updated as a field
|
||||
- otherwise recursively merge the value between original, updated, dest
|
||||
|
||||
### Associative Keys
|
||||
|
||||
Associative keys are used to identify "same" elements within 2 different lists, and merge them.
|
||||
The following fields are recognized as associative keys:
|
||||
|
||||
[` + "`" + `mountPath` + "`" + `, ` + "`" + `devicePath` + "`" + `, ` + "`" + `ip` + "`" + `, ` + "`" + `type` + "`" + `, ` + "`" + `topologyKey` + "`" + `, ` + "`" + `name` + "`" + `, ` + "`" + `containerPort` + "`" + `]
|
||||
|
||||
Any lists where all of the elements contain associative keys will be merged as associative lists.`
|
||||
219
cmd/config/cmddocs/commands/docs.go
Normal file
219
cmd/config/cmddocs/commands/docs.go
Normal file
@@ -0,0 +1,219 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by "mdtogo"; DO NOT EDIT.
|
||||
package commands
|
||||
|
||||
var CatShort = `Print Resource Config from a local directory.`
|
||||
var CatLong = `
|
||||
Print Resource Config from a local directory.
|
||||
|
||||
DIR:
|
||||
Path to local directory.
|
||||
`
|
||||
var CatExamples = `
|
||||
# print Resource config from a directory
|
||||
kyaml cat my-dir/
|
||||
|
||||
# wrap Resource config from a directory in an ResourceList
|
||||
kyaml cat my-dir/ --wrap-kind ResourceList --wrap-version config.kubernetes.io/v1alpha1 --function-config fn.yaml
|
||||
|
||||
# unwrap Resource config from a directory in an ResourceList
|
||||
... | kyaml cat`
|
||||
|
||||
var CountShort = `Count Resources Config from a local directory.`
|
||||
var CountLong = `
|
||||
Count Resources Config from a local directory.
|
||||
|
||||
DIR:
|
||||
Path to local directory.
|
||||
`
|
||||
var CountExamples = `
|
||||
# print Resource counts from a directory
|
||||
kyaml count my-dir/`
|
||||
|
||||
var FmtShort = `Format yaml configuration files.`
|
||||
var FmtLong = `
|
||||
Format yaml configuration files.
|
||||
|
||||
Fmt will format input by ordering fields and unordered list items in Kubernetes
|
||||
objects. Inputs may be directories, files or stdin, and their contents must
|
||||
include both apiVersion and kind fields.
|
||||
|
||||
- Stdin inputs are formatted and written to stdout
|
||||
- File inputs (args) are formatted and written back to the file
|
||||
- Directory inputs (args) are walked, each encountered .yaml and .yml file
|
||||
acts as an input
|
||||
|
||||
For inputs which contain multiple yaml documents separated by \n---\n,
|
||||
each document will be formatted and written back to the file in the original
|
||||
order.
|
||||
|
||||
Field ordering roughly follows the ordering defined in the source Kubernetes
|
||||
resource definitions (i.e. go structures), falling back on lexicographical
|
||||
sorting for unrecognized fields.
|
||||
|
||||
Unordered list item ordering is defined for specific Resource types and
|
||||
field paths.
|
||||
|
||||
- .spec.template.spec.containers (by element name)
|
||||
- .webhooks.rules.operations (by element value)
|
||||
`
|
||||
var FmtExamples = `
|
||||
# format file1.yaml and file2.yml
|
||||
kyaml fmt file1.yaml file2.yml
|
||||
|
||||
# format all *.yaml and *.yml recursively traversing directories
|
||||
kyaml fmt my-dir/
|
||||
|
||||
# format kubectl output
|
||||
kubectl get -o yaml deployments | kyaml fmt
|
||||
|
||||
# format kustomize output
|
||||
kustomize build | kyaml fmt`
|
||||
|
||||
var GrepShort = `Search for matching Resources in a directory or from stdin`
|
||||
var GrepLong = `
|
||||
Search for matching Resources in a directory or from stdin.
|
||||
|
||||
QUERY:
|
||||
Query to match expressed as 'path.to.field=value'.
|
||||
Maps and fields are matched as '.field-name' or '.map-key'
|
||||
List elements are matched as '[list-elem-field=field-value]'
|
||||
The value to match is expressed as '=value'
|
||||
'.' as part of a key or value can be escaped as '\.'
|
||||
|
||||
DIR:
|
||||
Path to local directory.
|
||||
`
|
||||
var GrepExamples = `
|
||||
# find Deployment Resources
|
||||
kyaml grep "kind=Deployment" my-dir/
|
||||
|
||||
# find Resources named nginx
|
||||
kyaml grep "metadata.name=nginx" my-dir/
|
||||
|
||||
# use tree to display matching Resources
|
||||
kyaml grep "metadata.name=nginx" my-dir/ | kyaml tree
|
||||
|
||||
# look for Resources matching a specific container image
|
||||
kyaml grep "spec.template.spec.containers[name=nginx].image=nginx:1\.7\.9" my-dir/ | kyaml tree`
|
||||
|
||||
var MergeShort = `Merge Resource configuration files`
|
||||
var MergeLong = `
|
||||
Merge Resource configuration files
|
||||
|
||||
Merge reads Kubernetes Resource yaml configuration files from stdin or sources packages and write
|
||||
the result to stdout or a destination package.
|
||||
|
||||
Resources are merged using the Resource [apiVersion, kind, name, namespace] as the key. If any of
|
||||
these are missing, merge will default the missing values to empty.
|
||||
|
||||
Resources specified later are high-precedence (the source) and Resources specified
|
||||
earlier are lower-precedence (the destination).
|
||||
|
||||
For information on merge rules, run:
|
||||
|
||||
kyaml docs merge
|
||||
`
|
||||
var MergeExamples = `
|
||||
cat resources_and_patches.yaml | kyaml merge > merged_resources.yaml`
|
||||
|
||||
var RunFnsShort = `Apply config functions to Resources.`
|
||||
var RunFnsLong = `
|
||||
Apply config functions to Resources.
|
||||
|
||||
run-fns sequentially invokes all config functions in the directly, providing Resources
|
||||
in the directory as input to the first function, and writing the output of the last
|
||||
function back to the directory.
|
||||
|
||||
The ordering of functions is determined by the order they are encountered when walking the
|
||||
directory. To clearly specify an ordering of functions, multiple functions may be
|
||||
declared in the same file, separated by '---' (the functions will be invoked in the
|
||||
order they appear in the file).
|
||||
|
||||
#### Arguments:
|
||||
|
||||
DIR:
|
||||
Path to local directory.
|
||||
|
||||
#### Config Functions:
|
||||
|
||||
Config functions are specified as Kubernetes types containing a metadata.configFn.container.image
|
||||
field. This fields tells run-fns how to invoke the container.
|
||||
|
||||
Example config function:
|
||||
|
||||
# in file example/fn.yaml
|
||||
apiVersion: fn.example.com/v1beta1
|
||||
kind: ExampleFunctionKind
|
||||
metadata:
|
||||
configFn:
|
||||
container:
|
||||
# function is invoked as a container running this image
|
||||
image: gcr.io/example/examplefunction:v1.0.1
|
||||
annotations:
|
||||
config.kubernetes.io/local-config: "true" # tools should ignore this
|
||||
spec:
|
||||
configField: configValue
|
||||
|
||||
In the preceding example, 'kyaml run-fns example/' would identify the function by
|
||||
the metadata.configFn field. It would then write all Resources in the directory to
|
||||
a container stdin (running the gcr.io/example/examplefunction:v1.0.1 image). It
|
||||
would then writer the container stdout back to example/, replacing the directory
|
||||
file contents.
|
||||
|
||||
See ` + "`" + `kyaml help docs-fn` + "`" + ` for more details on writing functions.
|
||||
`
|
||||
var RunFnsExamples = `
|
||||
kyaml run-fns example/`
|
||||
|
||||
var TreeShort = `Display Resource structure from a directory or stdin.`
|
||||
var TreeLong = `
|
||||
Display Resource structure from a directory or stdin.
|
||||
|
||||
kyaml tree may be used to print Resources in a directory or cluster, preserving structure
|
||||
|
||||
Args:
|
||||
|
||||
DIR:
|
||||
Path to local directory directory.
|
||||
|
||||
Resource fields may be printed as part of the Resources by specifying the fields as flags.
|
||||
|
||||
kyaml tree has build-in support for printing common fields, such as replicas, container images,
|
||||
container names, etc.
|
||||
|
||||
kyaml tree supports printing arbitrary fields using the '--field' flag.
|
||||
|
||||
By default, kyaml tree uses the directory structure for the tree structure, however when printing
|
||||
from the cluster, the Resource graph structure may be used instead.
|
||||
`
|
||||
var TreeExamples = `
|
||||
# print Resources using directory structure
|
||||
kyaml tree my-dir/
|
||||
|
||||
# print replicas, container name, and container image and fields for Resources
|
||||
kyaml tree my-dir --replicas --image --name
|
||||
|
||||
# print all common Resource fields
|
||||
kyaml tree my-dir/ --all
|
||||
|
||||
# print the "foo"" annotation
|
||||
kyaml tree my-dir/ --field "metadata.annotations.foo"
|
||||
|
||||
# print the "foo"" annotation
|
||||
kubectl get all -o yaml | kyaml tree my-dir/ --structure=graph \
|
||||
--field="status.conditions[type=Completed].status"
|
||||
|
||||
# print live Resources from a cluster using graph for structure
|
||||
kubectl get all -o yaml | kyaml tree --replicas --name --image --structure=graph
|
||||
|
||||
|
||||
# print live Resources using graph for structure
|
||||
kubectl get all,applications,releasetracks -o yaml | kyaml tree --structure=graph \
|
||||
--name --image --replicas \
|
||||
--field="status.conditions[type=Completed].status" \
|
||||
--field="status.conditions[type=Complete].status" \
|
||||
--field="status.conditions[type=Ready].status" \
|
||||
--field="status.conditions[type=ContainersReady].status"`
|
||||
91
cmd/config/docs/api-conventions/merge2.md
Normal file
91
cmd/config/docs/api-conventions/merge2.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# Merge (2-way)
|
||||
|
||||
2-way merges fields from a source to a destination, overriding the destination fields
|
||||
where they differ.
|
||||
|
||||
### Merge Rules
|
||||
|
||||
Fields are recursively merged using the following rules:
|
||||
|
||||
- scalars
|
||||
- if present only in the dest, it keeps its value
|
||||
- if present in the src and is non-null, take the src value -- if `null`, clear it
|
||||
- example src: `5`, dest: `3` => result: `5`
|
||||
|
||||
- non-associative lists -- lists without a merge key
|
||||
- if present only in the dest, it keeps its value
|
||||
- if present in the src and is non-null, take the src value -- if `null`, clear it
|
||||
- example src: `[1, 2, 3]`, dest: `[a, b, c]` => result: `[1, 2, 3]`
|
||||
|
||||
- map keys and fields -- paired by the map-key / field-name
|
||||
- if present only in the dest, it keeps its value
|
||||
- if present only in the src, it is added to the dest
|
||||
- if the field is present in both the src and dest, and the src value is
|
||||
`null`, the field is removed from the dest
|
||||
- if the field is present in both the src and dest, the value is recursively merged
|
||||
- example src: `{'key1': 'value1', 'key2': 'value2'}`,
|
||||
dest: `{'key2': 'value0', 'key3': 'value3'}`
|
||||
=> result: `{'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}`
|
||||
|
||||
- associative list elements -- paired by the associative key
|
||||
- if present only in the dest, it keeps its value in the list
|
||||
- if present only in the src, it is added to the dest list
|
||||
- if the field is present in both the src and dest, the value is recursively merged
|
||||
|
||||
### Associative Keys
|
||||
|
||||
Associative keys are used to identify "same" elements within 2 different lists, and merge them.
|
||||
The following fields are recognized as associative keys:
|
||||
|
||||
[`mountPath`, `devicePath`, `ip`, `type`, `topologyKey`, `name`, `containerPort`]
|
||||
|
||||
Any lists where all of the elements contain associative keys will be merged as associative lists.
|
||||
|
||||
### Example
|
||||
|
||||
> Source
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 3 # scalar
|
||||
template:
|
||||
spec:
|
||||
containers: # associative list -- (name)
|
||||
- name: nginx
|
||||
image: nginx:1.7
|
||||
command: ['new_run.sh', 'arg1'] # non-associative list
|
||||
- name: sidecar2
|
||||
image: sidecar2:v1
|
||||
|
||||
> Destination
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.6
|
||||
command: ['old_run.sh', 'arg0']
|
||||
- name: sidecar1
|
||||
image: sidecar1:v1
|
||||
|
||||
> Result
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 3 # scalar
|
||||
template:
|
||||
spec:
|
||||
containers: # associative list -- (name)
|
||||
- name: nginx
|
||||
image: nginx:1.7
|
||||
command: ['new_run.sh', 'arg1'] # non-associative list
|
||||
- name: sidecar1
|
||||
image: sidecar1:v1
|
||||
- name: sidecar2
|
||||
image: sidecar2:v1
|
||||
46
cmd/config/docs/api-conventions/merge3.md
Normal file
46
cmd/config/docs/api-conventions/merge3.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Merge (3-way)
|
||||
|
||||
3-way merge identifies changes between an original source + updated source and merges the result
|
||||
into a destination, overriding the destination fields where they have changed between
|
||||
original and updated.
|
||||
|
||||
### Resource MergeRules
|
||||
|
||||
- Resources present in the original and deleted from the update are deleted.
|
||||
- Resources missing from the original and added in the update are added.
|
||||
- Resources present only in the dest are kept without changes.
|
||||
- Resources present in both the update and the dest have their fields merged with the destination.
|
||||
|
||||
### Field Merge Rules
|
||||
|
||||
Fields are recursively merged using the following rules:
|
||||
|
||||
- scalars
|
||||
- if present in either dest or updated and `null`, clear the value
|
||||
- if unchanged between original and updated, keep dest value
|
||||
- if changed between original and updated (added, deleted, changed), take the updated value
|
||||
|
||||
- non-associative lists -- lists without a merge key
|
||||
- if present in either dest or updated and `null`, clear the value
|
||||
- if unchanged between original and updated, keep dest value
|
||||
- if changed between original and updated (added, deleted, changed), take the updated value
|
||||
|
||||
- map keys and fields -- paired by the map-key / field-name
|
||||
- if present in either dest or updated and `null`, clear the value
|
||||
- if present only in the dest, it keeps its value
|
||||
- if not-present in the dest, add the delta between original-updated as a field
|
||||
- otherwise recursively merge the value between original, updated, dest
|
||||
|
||||
- associative list elements -- paired by the associative key
|
||||
- if present only in the dest, it keeps its value
|
||||
- if not-present in the dest, add the delta between original-updated as a field
|
||||
- otherwise recursively merge the value between original, updated, dest
|
||||
|
||||
### Associative Keys
|
||||
|
||||
Associative keys are used to identify "same" elements within 2 different lists, and merge them.
|
||||
The following fields are recognized as associative keys:
|
||||
|
||||
[`mountPath`, `devicePath`, `ip`, `type`, `topologyKey`, `name`, `containerPort`]
|
||||
|
||||
Any lists where all of the elements contain associative keys will be merged as associative lists.
|
||||
21
cmd/config/docs/commands/cat.md
Normal file
21
cmd/config/docs/commands/cat.md
Normal file
@@ -0,0 +1,21 @@
|
||||
## cat
|
||||
|
||||
Print Resource Config from a local directory.
|
||||
|
||||
### Synopsis
|
||||
|
||||
Print Resource Config from a local directory.
|
||||
|
||||
DIR:
|
||||
Path to local directory.
|
||||
|
||||
### Examples
|
||||
|
||||
# print Resource config from a directory
|
||||
kyaml cat my-dir/
|
||||
|
||||
# wrap Resource config from a directory in an ResourceList
|
||||
kyaml cat my-dir/ --wrap-kind ResourceList --wrap-version config.kubernetes.io/v1alpha1 --function-config fn.yaml
|
||||
|
||||
# unwrap Resource config from a directory in an ResourceList
|
||||
... | kyaml cat
|
||||
15
cmd/config/docs/commands/count.md
Normal file
15
cmd/config/docs/commands/count.md
Normal file
@@ -0,0 +1,15 @@
|
||||
## count
|
||||
|
||||
Count Resources Config from a local directory.
|
||||
|
||||
### Synopsis
|
||||
|
||||
Count Resources Config from a local directory.
|
||||
|
||||
DIR:
|
||||
Path to local directory.
|
||||
|
||||
### Examples
|
||||
|
||||
# print Resource counts from a directory
|
||||
kyaml count my-dir/
|
||||
44
cmd/config/docs/commands/fmt.md
Normal file
44
cmd/config/docs/commands/fmt.md
Normal file
@@ -0,0 +1,44 @@
|
||||
## fmt
|
||||
|
||||
Format yaml configuration files.
|
||||
|
||||
### Synopsis
|
||||
|
||||
Format yaml configuration files.
|
||||
|
||||
Fmt will format input by ordering fields and unordered list items in Kubernetes
|
||||
objects. Inputs may be directories, files or stdin, and their contents must
|
||||
include both apiVersion and kind fields.
|
||||
|
||||
- Stdin inputs are formatted and written to stdout
|
||||
- File inputs (args) are formatted and written back to the file
|
||||
- Directory inputs (args) are walked, each encountered .yaml and .yml file
|
||||
acts as an input
|
||||
|
||||
For inputs which contain multiple yaml documents separated by \n---\n,
|
||||
each document will be formatted and written back to the file in the original
|
||||
order.
|
||||
|
||||
Field ordering roughly follows the ordering defined in the source Kubernetes
|
||||
resource definitions (i.e. go structures), falling back on lexicographical
|
||||
sorting for unrecognized fields.
|
||||
|
||||
Unordered list item ordering is defined for specific Resource types and
|
||||
field paths.
|
||||
|
||||
- .spec.template.spec.containers (by element name)
|
||||
- .webhooks.rules.operations (by element value)
|
||||
|
||||
### Examples
|
||||
|
||||
# format file1.yaml and file2.yml
|
||||
kyaml fmt file1.yaml file2.yml
|
||||
|
||||
# format all *.yaml and *.yml recursively traversing directories
|
||||
kyaml fmt my-dir/
|
||||
|
||||
# format kubectl output
|
||||
kubectl get -o yaml deployments | kyaml fmt
|
||||
|
||||
# format kustomize output
|
||||
kustomize build | kyaml fmt
|
||||
31
cmd/config/docs/commands/grep.md
Normal file
31
cmd/config/docs/commands/grep.md
Normal file
@@ -0,0 +1,31 @@
|
||||
## grep
|
||||
|
||||
Search for matching Resources in a directory or from stdin
|
||||
|
||||
### Synopsis
|
||||
|
||||
Search for matching Resources in a directory or from stdin.
|
||||
|
||||
QUERY:
|
||||
Query to match expressed as 'path.to.field=value'.
|
||||
Maps and fields are matched as '.field-name' or '.map-key'
|
||||
List elements are matched as '[list-elem-field=field-value]'
|
||||
The value to match is expressed as '=value'
|
||||
'.' as part of a key or value can be escaped as '\.'
|
||||
|
||||
DIR:
|
||||
Path to local directory.
|
||||
|
||||
### Examples
|
||||
|
||||
# find Deployment Resources
|
||||
kyaml grep "kind=Deployment" my-dir/
|
||||
|
||||
# find Resources named nginx
|
||||
kyaml grep "metadata.name=nginx" my-dir/
|
||||
|
||||
# use tree to display matching Resources
|
||||
kyaml grep "metadata.name=nginx" my-dir/ | kyaml tree
|
||||
|
||||
# look for Resources matching a specific container image
|
||||
kyaml grep "spec.template.spec.containers[name=nginx].image=nginx:1\.7\.9" my-dir/ | kyaml tree
|
||||
24
cmd/config/docs/commands/merge.md
Normal file
24
cmd/config/docs/commands/merge.md
Normal file
@@ -0,0 +1,24 @@
|
||||
## merge
|
||||
|
||||
Merge Resource configuration files
|
||||
|
||||
### Synopsis
|
||||
|
||||
Merge Resource configuration files
|
||||
|
||||
Merge reads Kubernetes Resource yaml configuration files from stdin or sources packages and write
|
||||
the result to stdout or a destination package.
|
||||
|
||||
Resources are merged using the Resource [apiVersion, kind, name, namespace] as the key. If any of
|
||||
these are missing, merge will default the missing values to empty.
|
||||
|
||||
Resources specified later are high-precedence (the source) and Resources specified
|
||||
earlier are lower-precedence (the destination).
|
||||
|
||||
For information on merge rules, run:
|
||||
|
||||
kyaml docs merge
|
||||
|
||||
### Examples
|
||||
|
||||
cat resources_and_patches.yaml | kyaml merge > merged_resources.yaml
|
||||
53
cmd/config/docs/commands/run-fns.md
Normal file
53
cmd/config/docs/commands/run-fns.md
Normal file
@@ -0,0 +1,53 @@
|
||||
## run-fns
|
||||
|
||||
Apply config functions to Resources.
|
||||
|
||||
### Synopsis
|
||||
|
||||
Apply config functions to Resources.
|
||||
|
||||
run-fns sequentially invokes all config functions in the directly, providing Resources
|
||||
in the directory as input to the first function, and writing the output of the last
|
||||
function back to the directory.
|
||||
|
||||
The ordering of functions is determined by the order they are encountered when walking the
|
||||
directory. To clearly specify an ordering of functions, multiple functions may be
|
||||
declared in the same file, separated by '---' (the functions will be invoked in the
|
||||
order they appear in the file).
|
||||
|
||||
#### Arguments:
|
||||
|
||||
DIR:
|
||||
Path to local directory.
|
||||
|
||||
#### Config Functions:
|
||||
|
||||
Config functions are specified as Kubernetes types containing a metadata.configFn.container.image
|
||||
field. This fields tells run-fns how to invoke the container.
|
||||
|
||||
Example config function:
|
||||
|
||||
# in file example/fn.yaml
|
||||
apiVersion: fn.example.com/v1beta1
|
||||
kind: ExampleFunctionKind
|
||||
metadata:
|
||||
configFn:
|
||||
container:
|
||||
# function is invoked as a container running this image
|
||||
image: gcr.io/example/examplefunction:v1.0.1
|
||||
annotations:
|
||||
config.kubernetes.io/local-config: "true" # tools should ignore this
|
||||
spec:
|
||||
configField: configValue
|
||||
|
||||
In the preceding example, 'kyaml run-fns example/' would identify the function by
|
||||
the metadata.configFn field. It would then write all Resources in the directory to
|
||||
a container stdin (running the gcr.io/example/examplefunction:v1.0.1 image). It
|
||||
would then writer the container stdout back to example/, replacing the directory
|
||||
file contents.
|
||||
|
||||
See `kyaml help docs-fn` for more details on writing functions.
|
||||
|
||||
### Examples
|
||||
|
||||
kyaml run-fns example/
|
||||
54
cmd/config/docs/commands/tree.md
Normal file
54
cmd/config/docs/commands/tree.md
Normal file
@@ -0,0 +1,54 @@
|
||||
## tree
|
||||
|
||||
Display Resource structure from a directory or stdin.
|
||||
|
||||
### Synopsis
|
||||
|
||||
Display Resource structure from a directory or stdin.
|
||||
|
||||
kyaml tree may be used to print Resources in a directory or cluster, preserving structure
|
||||
|
||||
Args:
|
||||
|
||||
DIR:
|
||||
Path to local directory directory.
|
||||
|
||||
Resource fields may be printed as part of the Resources by specifying the fields as flags.
|
||||
|
||||
kyaml tree has build-in support for printing common fields, such as replicas, container images,
|
||||
container names, etc.
|
||||
|
||||
kyaml tree supports printing arbitrary fields using the '--field' flag.
|
||||
|
||||
By default, kyaml tree uses the directory structure for the tree structure, however when printing
|
||||
from the cluster, the Resource graph structure may be used instead.
|
||||
|
||||
### Examples
|
||||
|
||||
# print Resources using directory structure
|
||||
kyaml tree my-dir/
|
||||
|
||||
# print replicas, container name, and container image and fields for Resources
|
||||
kyaml tree my-dir --replicas --image --name
|
||||
|
||||
# print all common Resource fields
|
||||
kyaml tree my-dir/ --all
|
||||
|
||||
# print the "foo"" annotation
|
||||
kyaml tree my-dir/ --field "metadata.annotations.foo"
|
||||
|
||||
# print the "foo"" annotation
|
||||
kubectl get all -o yaml | kyaml tree my-dir/ --structure=graph \
|
||||
--field="status.conditions[type=Completed].status"
|
||||
|
||||
# print live Resources from a cluster using graph for structure
|
||||
kubectl get all -o yaml | kyaml tree --replicas --name --image --structure=graph
|
||||
|
||||
|
||||
# print live Resources using graph for structure
|
||||
kubectl get all,applications,releasetracks -o yaml | kyaml tree --structure=graph \
|
||||
--name --image --replicas \
|
||||
--field="status.conditions[type=Completed].status" \
|
||||
--field="status.conditions[type=Complete].status" \
|
||||
--field="status.conditions[type=Ready].status" \
|
||||
--field="status.conditions[type=ContainersReady].status"
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:generate $GOBIN/mdtogo docs/api-conventions cmddocs/api --full=true
|
||||
//go:generate $GOBIN/mdtogo docs/commands cmddocs/commands
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -8,33 +10,39 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/cmd"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/merge2"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/merge3"
|
||||
"sigs.k8s.io/kustomize/cmd/config/cmddocs/api"
|
||||
)
|
||||
|
||||
var root = &cobra.Command{
|
||||
Use: "kyaml",
|
||||
Short: "kyaml reference comand",
|
||||
Long: `Description:
|
||||
Reference implementation for using the kyaml libraries.
|
||||
`,
|
||||
Example: ``,
|
||||
Use: "config",
|
||||
Short: "Utilities for working with Resource Configuration.",
|
||||
Long: `Utilities for working with Resource Configuration.`,
|
||||
}
|
||||
|
||||
func main() {
|
||||
root.PersistentFlags().BoolVar(&cmd.StackOnError, "stack-trace", false,
|
||||
"print a stack-trace on failure")
|
||||
|
||||
name := "config"
|
||||
cmd.ExitOnError = true
|
||||
root.AddCommand(cmd.GrepCommand())
|
||||
root.AddCommand(cmd.TreeCommand())
|
||||
root.AddCommand(cmd.CatCommand())
|
||||
root.AddCommand(cmd.FmtCommand())
|
||||
root.AddCommand(cmd.MergeCommand())
|
||||
root.AddCommand(cmd.CountCommand())
|
||||
root.AddCommand(cmd.RunFnCommand())
|
||||
root.AddCommand(&cobra.Command{Use: "merge", Long: merge2.Help})
|
||||
root.AddCommand(&cobra.Command{Use: "merge3", Long: merge3.Help})
|
||||
root.AddCommand(cmd.GrepCommand(name))
|
||||
root.AddCommand(cmd.TreeCommand(name))
|
||||
root.AddCommand(cmd.CatCommand(name))
|
||||
root.AddCommand(cmd.FmtCommand(name))
|
||||
root.AddCommand(cmd.MergeCommand(name))
|
||||
root.AddCommand(cmd.CountCommand(name))
|
||||
root.AddCommand(cmd.RunFnCommand(name))
|
||||
|
||||
root.AddCommand(&cobra.Command{
|
||||
Use: "docs-merge",
|
||||
Short: "Documentation for merging Resources (2-way merge).",
|
||||
Long: api.Merge2Long,
|
||||
})
|
||||
root.AddCommand(&cobra.Command{
|
||||
Use: "docs-merge3",
|
||||
Short: "Documentation for merging Resources (3-way merge).",
|
||||
Long: api.Merge3Long,
|
||||
})
|
||||
|
||||
if err := root.Execute(); err != nil {
|
||||
os.Exit(1)
|
||||
|
||||
@@ -10,97 +10,6 @@ import (
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/walk"
|
||||
)
|
||||
|
||||
const Help = `
|
||||
Description:
|
||||
|
||||
merge merges fields from a source to a destination, overriding the destination fields
|
||||
where they differ.
|
||||
|
||||
### Merge Rules
|
||||
|
||||
Fields are recursively merged using the following rules:
|
||||
|
||||
- scalars
|
||||
- if present only in the dest, it keeps its value
|
||||
- if present in the src and is non-null, take the src value -- if ` + "`null`" + `, clear it
|
||||
` + " - example src: `5`, dest: `3` => result: `5`" + `
|
||||
|
||||
- non-associative lists -- lists without a merge key
|
||||
- if present only in the dest, it keeps its value
|
||||
- if present in the src and is non-null, take the src value -- if ` + "`null`" + `, clear it
|
||||
` + " - example src: `[1, 2, 3]`, dest: `[a, b, c]` => result: `[1, 2, 3]`" + `
|
||||
|
||||
- map keys and fields -- paired by the map-key / field-name
|
||||
- if present only in the dest, it keeps its value
|
||||
- if present only in the src, it is added to the dest
|
||||
- if the field is present in both the src and dest, and the src value is 'null', the field is removed from the dest
|
||||
- if the field is present in both the src and dest, the value is recursively merged
|
||||
` + " - example src: `{'key1': 'value1', 'key2': 'value2'}`, dest: `{'key2': 'value0', 'key3': 'value3'}` => result: `{'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}`" + `
|
||||
|
||||
- associative list elements -- paired by the associative key
|
||||
- if present only in the dest, it keeps its value in the list
|
||||
- if present only in the src, it is added to the dest list
|
||||
- if the field is present in both the src and dest, the value is recursively merged
|
||||
|
||||
### Associative Keys
|
||||
|
||||
Associative keys are used to identify "same" elements within 2 different lists, and merge them.
|
||||
The following fields are recognized as associative keys:
|
||||
|
||||
` + "[`mountPath`, `devicePath`, `ip`, `type`, `topologyKey`, `name`, `containerPort`]" + `
|
||||
|
||||
Any lists where all of the elements contain associative keys will be merged as associative lists.
|
||||
|
||||
### Example
|
||||
|
||||
> Source
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 3 # scalar
|
||||
template:
|
||||
spec:
|
||||
containers: # associative list -- (name)
|
||||
- name: nginx
|
||||
image: nginx:1.7
|
||||
command: ['new_run.sh', 'arg1'] # non-associative list
|
||||
- name: sidecar2
|
||||
image: sidecar2:v1
|
||||
|
||||
> Destination
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.6
|
||||
command: ['old_run.sh', 'arg0']
|
||||
- name: sidecar1
|
||||
image: sidecar1:v1
|
||||
|
||||
> Result
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 3 # scalar
|
||||
template:
|
||||
spec:
|
||||
containers: # associative list -- (name)
|
||||
- name: nginx
|
||||
image: nginx:1.7
|
||||
command: ['new_run.sh', 'arg1'] # non-associative list
|
||||
- name: sidecar1
|
||||
image: sidecar1:v1
|
||||
- name: sidecar2
|
||||
image: sidecar2:v1
|
||||
`
|
||||
|
||||
// Merge merges fields from src into dest.
|
||||
func Merge(src, dest *yaml.RNode) (*yaml.RNode, error) {
|
||||
return walk.Walker{Sources: []*yaml.RNode{dest, src}, Visitor: Merger{}}.Walk()
|
||||
|
||||
@@ -10,55 +10,6 @@ import (
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/walk"
|
||||
)
|
||||
|
||||
const Help = `
|
||||
Description:
|
||||
|
||||
merge3 identifies changes between an original source + updated source and merges the result
|
||||
into a destination, overriding the destination fields where they have changed between
|
||||
original and updated.
|
||||
|
||||
### Resource MergeRules
|
||||
|
||||
- Resources present in the original and deleted from the update are deleted.
|
||||
- Resources missing from the original and added in the update are added.
|
||||
- Resources present only in the dest are kept without changes.
|
||||
- Resources present in both the update and the dest are merged *original + update + dest => dest*.
|
||||
|
||||
### Field Merge Rules
|
||||
|
||||
Fields are recursively merged using the following rules:
|
||||
|
||||
- scalars
|
||||
- if present in either dest or updated and 'null', clear the value
|
||||
- if unchanged between original and updated, keep dest value
|
||||
- if changed between original and updated (added, deleted, changed), take the updated value
|
||||
|
||||
- non-associative lists -- lists without a merge key
|
||||
- if present in either dest or updated and 'null', clear the value
|
||||
- if unchanged between original and updated, keep dest value
|
||||
- if changed between original and updated (added, deleted, changed), take the updated value
|
||||
|
||||
- map keys and fields -- paired by the map-key / field-name
|
||||
- if present in either dest or updated and 'null', clear the value
|
||||
- if present only in the dest, it keeps its value
|
||||
- if not-present in the dest, add the delta between original-updated as a field
|
||||
- otherwise recursively merge the value between original, updated, dest
|
||||
|
||||
- associative list elements -- paired by the associative key
|
||||
- if present only in the dest, it keeps its value
|
||||
- if not-present in the dest, add the delta between original-updated as a field
|
||||
- otherwise recursively merge the value between original, updated, dest
|
||||
|
||||
### Associative Keys
|
||||
|
||||
Associative keys are used to identify "same" elements within 2 different lists, and merge them.
|
||||
The following fields are recognized as associative keys:
|
||||
|
||||
` + "[`mountPath`, `devicePath`, `ip`, `type`, `topologyKey`, `name`, `containerPort`]" + `
|
||||
|
||||
Any lists where all of the elements contain associative keys will be merged as associative lists.
|
||||
`
|
||||
|
||||
func Merge(dest, original, update *yaml.RNode) (*yaml.RNode, error) {
|
||||
// if update == nil && original != nil => declarative deletion
|
||||
|
||||
|
||||
Reference in New Issue
Block a user