From 90e1dbe5d05182d3b49b89fb7b706ca0d498c3f8 Mon Sep 17 00:00:00 2001 From: Phillip Wittrock Date: Wed, 5 Feb 2020 16:08:02 -0800 Subject: [PATCH] cmd/config: support for stdin/stdout in source/sink --- cmd/config/docs/commands/sink.md | 4 +- cmd/config/docs/commands/source.md | 5 +- cmd/config/internal/commands/sink.go | 23 ++-- cmd/config/internal/commands/sink_test.go | 117 +++++++++++++++++- cmd/config/internal/commands/source.go | 13 +- cmd/config/internal/commands/source_test.go | 64 ++++++++++ .../internal/generateddocs/commands/docs.go | 9 +- 7 files changed, 211 insertions(+), 24 deletions(-) diff --git a/cmd/config/docs/commands/sink.md b/cmd/config/docs/commands/sink.md index ed31de43e..264fb66ac 100644 --- a/cmd/config/docs/commands/sink.md +++ b/cmd/config/docs/commands/sink.md @@ -6,10 +6,10 @@ [Alpha] Implement a Sink by writing input to a local directory. - kustomize config sink DIR + kustomize config sink [DIR] DIR: - Path to local directory. + Path to local directory. If unspecified, sink will write to stdout as if it were a single file. `sink` writes its input to a directory diff --git a/cmd/config/docs/commands/source.md b/cmd/config/docs/commands/source.md index 66f12e9f8..978277b38 100644 --- a/cmd/config/docs/commands/source.md +++ b/cmd/config/docs/commands/source.md @@ -6,10 +6,11 @@ [Alpha] Implement a Source by reading a local directory. - kustomize config source DIR + kustomize config source DIR... DIR: - Path to local directory. + One or more paths to local directories. Contents from directories will be concatenated. + If no directories are provided, source will read from stdin as if it were a single file. `source` emits configuration to act as input to a function diff --git a/cmd/config/internal/commands/sink.go b/cmd/config/internal/commands/sink.go index f1b05d9d6..74e1ec8a3 100644 --- a/cmd/config/internal/commands/sink.go +++ b/cmd/config/internal/commands/sink.go @@ -7,6 +7,7 @@ import ( "github.com/spf13/cobra" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/kio/kioutil" ) // GetSinkRunner returns a command for Sink. @@ -18,7 +19,7 @@ func GetSinkRunner(name string) *SinkRunner { Long: commands.SinkLong, Example: commands.SinkExamples, RunE: r.runE, - Args: cobra.ExactArgs(1), + Args: cobra.MaximumNArgs(1), } fixDocs(name, c) r.Command = c @@ -35,14 +36,18 @@ type SinkRunner struct { } func (r *SinkRunner) runE(c *cobra.Command, args []string) error { + var outputs []kio.Writer + if len(args) == 1 { + outputs = []kio.Writer{&kio.LocalPackageWriter{PackagePath: args[0]}} + } else { + outputs = []kio.Writer{&kio.ByteWriter{ + Writer: c.OutOrStdout(), + ClearAnnotations: []string{kioutil.PathAnnotation}}, + } + } + err := kio.Pipeline{ - Inputs: []kio.Reader{&kio.ByteReader{Reader: c.InOrStdin()}}, - Outputs: []kio.Writer{ - &kio.LocalPackageWriter{ - PackagePath: args[0], - ClearAnnotations: []string{"config.kubernetes.io/path"}, - }, - }, - }.Execute() + Inputs: []kio.Reader{&kio.ByteReader{Reader: c.InOrStdin()}}, + Outputs: outputs}.Execute() return handleError(c, err) } diff --git a/cmd/config/internal/commands/sink_test.go b/cmd/config/internal/commands/sink_test.go index d09e9bd6f..9fc4d869c 100644 --- a/cmd/config/internal/commands/sink_test.go +++ b/cmd/config/internal/commands/sink_test.go @@ -21,8 +21,6 @@ func TestSinkCommand(t *testing.T) { } defer os.RemoveAll(d) - // fmt the files - b := &bytes.Buffer{} r := commands.GetSinkRunner("") r.Command.SetIn(bytes.NewBufferString(`apiVersion: config.kubernetes.io/v1alpha1 kind: ResourceList @@ -75,7 +73,6 @@ items: replicas: 3 `)) r.Command.SetArgs([]string{d}) - r.Command.SetOut(b) if !assert.NoError(t, r.Command.Execute()) { t.FailNow() } @@ -138,3 +135,117 @@ spec: t.FailNow() } } + +func TestSinkCommand_Stdout(t *testing.T) { + d, err := ioutil.TempDir("", "kustomize-source-test") + if !assert.NoError(t, err) { + t.FailNow() + } + defer os.RemoveAll(d) + + // fmt the files + out := &bytes.Buffer{} + r := commands.GetSinkRunner("") + r.Command.SetIn(bytes.NewBufferString(`apiVersion: config.kubernetes.io/v1alpha1 +kind: ResourceList +items: +- kind: Deployment + metadata: + labels: + app: nginx2 + name: foo + annotations: + app: nginx2 + config.kubernetes.io/index: '0' + config.kubernetes.io/path: 'f1.yaml' + spec: + replicas: 1 +- kind: Service + metadata: + name: foo + annotations: + app: nginx + config.kubernetes.io/index: '1' + config.kubernetes.io/path: 'f1.yaml' + spec: + selector: + app: nginx +- apiVersion: v1 + kind: Abstraction + metadata: + name: foo + annotations: + config.kubernetes.io/function: | + container: + image: gcr.io/example/reconciler:v1 + config.kubernetes.io/local-config: "true" + config.kubernetes.io/index: '0' + config.kubernetes.io/path: 'f2.yaml' + spec: + replicas: 3 +- apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + app: nginx + name: bar + annotations: + app: nginx + config.kubernetes.io/index: '1' + config.kubernetes.io/path: 'f2.yaml' + spec: + replicas: 3 +`)) + + r.Command.SetOut(out) + r.Command.SetArgs([]string{}) + if !assert.NoError(t, r.Command.Execute()) { + t.FailNow() + } + + expected := `kind: Deployment +metadata: + labels: + app: nginx2 + name: foo + annotations: + app: nginx2 +spec: + replicas: 1 +--- +kind: Service +metadata: + name: foo + annotations: + app: nginx +spec: + selector: + app: nginx +--- +apiVersion: v1 +kind: Abstraction +metadata: + name: foo + annotations: + config.kubernetes.io/function: | + container: + image: gcr.io/example/reconciler:v1 + config.kubernetes.io/local-config: "true" +spec: + replicas: 3 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: bar + annotations: + app: nginx +spec: + replicas: 3 +` + if !assert.Equal(t, expected, out.String()) { + t.FailNow() + } +} diff --git a/cmd/config/internal/commands/source.go b/cmd/config/internal/commands/source.go index 5926d3af9..27382bb2f 100644 --- a/cmd/config/internal/commands/source.go +++ b/cmd/config/internal/commands/source.go @@ -21,7 +21,6 @@ func GetSourceRunner(name string) *SourceRunner { Long: commands.SourceLong, Example: commands.SourceExamples, RunE: r.runE, - Args: cobra.ExactArgs(1), } fixDocs(name, c) c.Flags().StringVar(&r.WrapKind, "wrap-kind", kio.ResourceListKind, @@ -70,8 +69,14 @@ func (r *SourceRunner) runE(c *cobra.Command, args []string) error { FunctionConfig: functionConfig, }) - err := kio.Pipeline{ - Inputs: []kio.Reader{kio.LocalPackageReader{PackagePath: args[0]}}, - Outputs: outputs}.Execute() + var inputs []kio.Reader + for _, a := range args { + inputs = append(inputs, kio.LocalPackageReader{PackagePath: a}) + } + if len(inputs) == 0 { + inputs = []kio.Reader{&kio.ByteReader{Reader: c.InOrStdin()}} + } + + err := kio.Pipeline{Inputs: inputs, Outputs: outputs}.Execute() return handleError(c, err) } diff --git a/cmd/config/internal/commands/source_test.go b/cmd/config/internal/commands/source_test.go index a4c01bb1c..141541143 100644 --- a/cmd/config/internal/commands/source_test.go +++ b/cmd/config/internal/commands/source_test.go @@ -134,3 +134,67 @@ items: return } } + +func TestSourceCommand_Stdin(t *testing.T) { + d, err := ioutil.TempDir("", "kustomize-source-test") + if !assert.NoError(t, err) { + return + } + defer os.RemoveAll(d) + + in := bytes.NewBufferString(` +kind: Deployment +metadata: + labels: + app: nginx2 + name: foo + annotations: + app: nginx2 +spec: + replicas: 1 +--- +kind: Service +metadata: + name: foo + annotations: + app: nginx +spec: + selector: + app: nginx +`) + + out := &bytes.Buffer{} + r := commands.GetSourceRunner("") + r.Command.SetArgs([]string{}) + r.Command.SetIn(in) + r.Command.SetOut(out) + if !assert.NoError(t, r.Command.Execute()) { + return + } + + if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1 +kind: ResourceList +items: +- kind: Deployment + metadata: + labels: + app: nginx2 + name: foo + annotations: + app: nginx2 + config.kubernetes.io/index: '0' + spec: + replicas: 1 +- kind: Service + metadata: + name: foo + annotations: + app: nginx + config.kubernetes.io/index: '1' + spec: + selector: + app: nginx +`, out.String()) { + return + } +} diff --git a/cmd/config/internal/generateddocs/commands/docs.go b/cmd/config/internal/generateddocs/commands/docs.go index b4cfce577..7c500a51d 100644 --- a/cmd/config/internal/generateddocs/commands/docs.go +++ b/cmd/config/internal/generateddocs/commands/docs.go @@ -350,10 +350,10 @@ var SinkShort = `[Alpha] Implement a Sink by writing input to a local directory. var SinkLong = ` [Alpha] Implement a Sink by writing input to a local directory. - kustomize config sink DIR + kustomize config sink [DIR] DIR: - Path to local directory. + Path to local directory. If unspecified, sink will write to stdout as if it were a single file. ` + "`" + `sink` + "`" + ` writes its input to a directory ` @@ -364,10 +364,11 @@ var SourceShort = `[Alpha] Implement a Source by reading a local directory.` var SourceLong = ` [Alpha] Implement a Source by reading a local directory. - kustomize config source DIR + kustomize config source DIR... DIR: - Path to local directory. + One or more paths to local directories. Contents from directories will be concatenated. + If no directories are provided, source will read from stdin as if it were a single file. ` + "`" + `source` + "`" + ` emits configuration to act as input to a function `