From 8d6ab207539c93003a94c8ca984b07cbb6e30825 Mon Sep 17 00:00:00 2001 From: Jingfang Liu Date: Mon, 11 Feb 2019 16:43:57 -0800 Subject: [PATCH] add kustomize as a subcommand in kubectl --- build/visible_to/BUILD | 1 + pkg/kubectl/cmd/BUILD | 2 + pkg/kubectl/cmd/cmd.go | 2 + pkg/kubectl/cmd/kustomize/BUILD | 36 ++++++++ pkg/kubectl/cmd/kustomize/kustomize.go | 92 +++++++++++++++++++++ pkg/kubectl/cmd/kustomize/kustomize_test.go | 56 +++++++++++++ 6 files changed, 189 insertions(+) create mode 100644 pkg/kubectl/cmd/kustomize/BUILD create mode 100644 pkg/kubectl/cmd/kustomize/kustomize.go create mode 100644 pkg/kubectl/cmd/kustomize/kustomize_test.go diff --git a/build/visible_to/BUILD b/build/visible_to/BUILD index baf30d938aa..02d5f80657a 100644 --- a/build/visible_to/BUILD +++ b/build/visible_to/BUILD @@ -193,6 +193,7 @@ package_group( "//pkg/kubectl/cmd/expose", "//pkg/kubectl/cmd/get", "//pkg/kubectl/cmd/help", + "//pkg/kubectl/cmd/kustomize", "//pkg/kubectl/cmd/label", "//pkg/kubectl/cmd/logs", "//pkg/kubectl/cmd/options", diff --git a/pkg/kubectl/cmd/BUILD b/pkg/kubectl/cmd/BUILD index 89ec72bf71f..8e2ade844df 100644 --- a/pkg/kubectl/cmd/BUILD +++ b/pkg/kubectl/cmd/BUILD @@ -38,6 +38,7 @@ go_library( "//pkg/kubectl/cmd/explain:go_default_library", "//pkg/kubectl/cmd/expose:go_default_library", "//pkg/kubectl/cmd/get:go_default_library", + "//pkg/kubectl/cmd/kustomize:go_default_library", "//pkg/kubectl/cmd/label:go_default_library", "//pkg/kubectl/cmd/logs:go_default_library", "//pkg/kubectl/cmd/options:go_default_library", @@ -116,6 +117,7 @@ filegroup( "//pkg/kubectl/cmd/expose:all-srcs", "//pkg/kubectl/cmd/get:all-srcs", "//pkg/kubectl/cmd/help:all-srcs", + "//pkg/kubectl/cmd/kustomize:all-srcs", "//pkg/kubectl/cmd/label:all-srcs", "//pkg/kubectl/cmd/logs:all-srcs", "//pkg/kubectl/cmd/options:all-srcs", diff --git a/pkg/kubectl/cmd/cmd.go b/pkg/kubectl/cmd/cmd.go index df2be6d44f2..2b7e2eed1a1 100644 --- a/pkg/kubectl/cmd/cmd.go +++ b/pkg/kubectl/cmd/cmd.go @@ -73,6 +73,7 @@ import ( "k8s.io/kubernetes/pkg/kubectl/util/templates" "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/kubernetes/pkg/kubectl/cmd/kustomize" ) const ( @@ -521,6 +522,7 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command { replace.NewCmdReplace(f, ioStreams), wait.NewCmdWait(f, ioStreams), convert.NewCmdConvert(f, ioStreams), + kustomize.NewCmdKustomize(ioStreams), }, }, { diff --git a/pkg/kubectl/cmd/kustomize/BUILD b/pkg/kubectl/cmd/kustomize/BUILD new file mode 100644 index 00000000000..917db7bcc87 --- /dev/null +++ b/pkg/kubectl/cmd/kustomize/BUILD @@ -0,0 +1,36 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["kustomize.go"], + importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/kustomize", + visibility = ["//visibility:public"], + deps = [ + "//pkg/kubectl/util/i18n:go_default_library", + "//pkg/kubectl/util/templates:go_default_library", + "//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library", + "//staging/src/k8s.io/cli-runtime/pkg/kustomize:go_default_library", + "//vendor/github.com/spf13/cobra:go_default_library", + "//vendor/sigs.k8s.io/kustomize/pkg/fs:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) + +go_test( + name = "go_default_test", + srcs = ["kustomize_test.go"], + embed = [":go_default_library"], +) diff --git a/pkg/kubectl/cmd/kustomize/kustomize.go b/pkg/kubectl/cmd/kustomize/kustomize.go new file mode 100644 index 00000000000..dcd5a1c3985 --- /dev/null +++ b/pkg/kubectl/cmd/kustomize/kustomize.go @@ -0,0 +1,92 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kustomize + +import ( + "errors" + "github.com/spf13/cobra" + + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/kustomize" + "k8s.io/kubernetes/pkg/kubectl/util/i18n" + "k8s.io/kubernetes/pkg/kubectl/util/templates" + "sigs.k8s.io/kustomize/pkg/fs" +) + +type kustomizeOptions struct { + kustomizationDir string +} + +var ( + kustomizeLong = templates.LongDesc(i18n.T(` +Print a set of API resources generated from instructions in a kustomization.yaml file. + +The argument must be the path to the directory containing +the file, or a git repository +URL with a path suffix specifying same with respect to the +repository root. + + kubectl kustomize somedir + `)) + + kustomizeExample = templates.Examples(i18n.T(` +# Use the current working directory + kubectl kustomize . + +# Use some shared configuration directory + kubectl kustomize /home/configuration/production + +# Use a URL + kubectl kustomize github.com/kubernetes-sigs/kustomize.git/examples/helloWorld?ref=v1.0.6 +`)) +) + +// NewCmdKustomize returns a kustomize command +func NewCmdKustomize(streams genericclioptions.IOStreams) *cobra.Command { + var o kustomizeOptions + + cmd := &cobra.Command{ + Use: "kustomize ", + Short: i18n.T("Build a kustomization target from a directory or a remote url."), + Long: kustomizeLong, + Example: kustomizeExample, + + RunE: func(cmd *cobra.Command, args []string) error { + err := o.Validate(args) + if err != nil { + return err + } + return kustomize.RunKustomizeBuild(streams.Out, fs.MakeRealFS(), o.kustomizationDir) + }, + } + + return cmd +} + +// Validate validates build command. +func (o *kustomizeOptions) Validate(args []string) error { + if len(args) > 1 { + return errors.New("specify one path to a kustomization directory") + } + if len(args) == 0 { + o.kustomizationDir = "./" + } else { + o.kustomizationDir = args[0] + } + + return nil +} diff --git a/pkg/kubectl/cmd/kustomize/kustomize_test.go b/pkg/kubectl/cmd/kustomize/kustomize_test.go new file mode 100644 index 00000000000..3143b1de2b2 --- /dev/null +++ b/pkg/kubectl/cmd/kustomize/kustomize_test.go @@ -0,0 +1,56 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kustomize + +import ( + "testing" +) + +func TestValidate(t *testing.T) { + var cases = []struct { + name string + args []string + path string + erMsg string + }{ + {"noargs", []string{}, "./", ""}, + {"file", []string{"beans"}, "beans", ""}, + {"path", []string{"a/b/c"}, "a/b/c", ""}, + {"path", []string{"too", "many"}, + "", "specify one path to a kustomization directory"}, + } + for _, mycase := range cases { + opts := kustomizeOptions{} + e := opts.Validate(mycase.args) + if len(mycase.erMsg) > 0 { + if e == nil { + t.Errorf("%s: Expected an error %v", mycase.name, mycase.erMsg) + } + if e.Error() != mycase.erMsg { + t.Errorf("%s: Expected error %s, but got %v", mycase.name, mycase.erMsg, e) + } + continue + } + if e != nil { + t.Errorf("%s: unknown error %v", mycase.name, e) + continue + } + if opts.kustomizationDir != mycase.path { + t.Errorf("%s: expected path '%s', got '%s'", mycase.name, mycase.path, opts.kustomizationDir) + } + } +}