mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 18:43:34 +00:00
vendor update for CSI 0.3.0
This commit is contained in:
84
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/BUILD
generated
vendored
84
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/BUILD
generated
vendored
@ -9,6 +9,7 @@ go_library(
|
||||
srcs = [
|
||||
"alpha.go",
|
||||
"annotate.go",
|
||||
"apiresources.go",
|
||||
"apiversions.go",
|
||||
"apply.go",
|
||||
"apply_edit_last_applied.go",
|
||||
@ -23,22 +24,8 @@ go_library(
|
||||
"completion.go",
|
||||
"convert.go",
|
||||
"cp.go",
|
||||
"create.go",
|
||||
"create_clusterrole.go",
|
||||
"create_clusterrolebinding.go",
|
||||
"create_configmap.go",
|
||||
"create_deployment.go",
|
||||
"create_job.go",
|
||||
"create_namespace.go",
|
||||
"create_pdb.go",
|
||||
"create_priorityclass.go",
|
||||
"create_quota.go",
|
||||
"create_role.go",
|
||||
"create_rolebinding.go",
|
||||
"create_secret.go",
|
||||
"create_service.go",
|
||||
"create_serviceaccount.go",
|
||||
"delete.go",
|
||||
"delete_flags.go",
|
||||
"describe.go",
|
||||
"diff.go",
|
||||
"drain.go",
|
||||
@ -74,30 +61,37 @@ go_library(
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/core/validation:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/batch/internalversion:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/apply/parse:go_default_library",
|
||||
"//pkg/kubectl/apply/strategy:go_default_library",
|
||||
"//pkg/kubectl/cmd/auth:go_default_library",
|
||||
"//pkg/kubectl/cmd/config:go_default_library",
|
||||
"//pkg/kubectl/cmd/resource:go_default_library",
|
||||
"//pkg/kubectl/cmd/create:go_default_library",
|
||||
"//pkg/kubectl/cmd/get:go_default_library",
|
||||
"//pkg/kubectl/cmd/rollout:go_default_library",
|
||||
"//pkg/kubectl/cmd/scalejob:go_default_library",
|
||||
"//pkg/kubectl/cmd/set:go_default_library",
|
||||
"//pkg/kubectl/cmd/templates:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/editor:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/openapi:go_default_library",
|
||||
"//pkg/kubectl/cmd/wait:go_default_library",
|
||||
"//pkg/kubectl/explain:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/printers:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/resource:go_default_library",
|
||||
"//pkg/kubectl/metricsutil:go_default_library",
|
||||
"//pkg/kubectl/plugins:go_default_library",
|
||||
"//pkg/kubectl/polymorphichelpers:go_default_library",
|
||||
"//pkg/kubectl/proxy:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
"//pkg/kubectl/scheme:go_default_library",
|
||||
"//pkg/kubectl/util:go_default_library",
|
||||
"//pkg/kubectl/util/i18n:go_default_library",
|
||||
"//pkg/kubectl/util/term:go_default_library",
|
||||
"//pkg/kubectl/validation:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//pkg/printers/internalversion:go_default_library",
|
||||
"//pkg/util/interrupt:go_default_library",
|
||||
"//pkg/util/taints:go_default_library",
|
||||
"//pkg/version:go_default_library",
|
||||
@ -111,16 +105,15 @@ go_library(
|
||||
"//vendor/github.com/renstrom/dedent:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||
"//vendor/k8s.io/api/batch/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/batch/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/autoscaling/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/policy/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
@ -134,6 +127,7 @@ go_library(
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
|
||||
@ -141,11 +135,12 @@ go_library(
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
|
||||
"//vendor/k8s.io/client-go/discovery:go_default_library",
|
||||
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/batch/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/rbac/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/scale:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/portforward:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
|
||||
@ -165,24 +160,10 @@ go_test(
|
||||
"apply_test.go",
|
||||
"attach_test.go",
|
||||
"clusterinfo_dump_test.go",
|
||||
"cmd_printing_test.go",
|
||||
"cmd_test.go",
|
||||
"convert_test.go",
|
||||
"cp_test.go",
|
||||
"create_clusterrole_test.go",
|
||||
"create_clusterrolebinding_test.go",
|
||||
"create_configmap_test.go",
|
||||
"create_deployment_test.go",
|
||||
"create_job_test.go",
|
||||
"create_namespace_test.go",
|
||||
"create_pdb_test.go",
|
||||
"create_priorityclass_test.go",
|
||||
"create_quota_test.go",
|
||||
"create_role_test.go",
|
||||
"create_rolebinding_test.go",
|
||||
"create_secret_test.go",
|
||||
"create_service_test.go",
|
||||
"create_serviceaccount_test.go",
|
||||
"create_test.go",
|
||||
"delete_test.go",
|
||||
"describe_test.go",
|
||||
"diff_test.go",
|
||||
@ -206,7 +187,6 @@ go_test(
|
||||
data = [
|
||||
"testdata",
|
||||
"//api/openapi-spec:swagger-spec",
|
||||
"//examples:config",
|
||||
"//test/e2e/testing-manifests:all-srcs",
|
||||
"//test/fixtures",
|
||||
],
|
||||
@ -218,29 +198,25 @@ go_test(
|
||||
"//pkg/apis/batch:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/cmd/resource:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/kubectl/cmd/create:go_default_library",
|
||||
"//pkg/kubectl/cmd/testing:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/openapi:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/printers:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/resource:go_default_library",
|
||||
"//pkg/kubectl/plugins:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
"//pkg/kubectl/polymorphichelpers:go_default_library",
|
||||
"//pkg/kubectl/scheme:go_default_library",
|
||||
"//pkg/kubectl/util/i18n:go_default_library",
|
||||
"//pkg/kubectl/util/term:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//pkg/util/strings:go_default_library",
|
||||
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/gopkg.in/yaml.v2:go_default_library",
|
||||
"//vendor/k8s.io/api/batch/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/batch/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/policy/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
@ -256,8 +232,7 @@ go_test(
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch/testing:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
|
||||
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/dynamic/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
@ -281,13 +256,16 @@ filegroup(
|
||||
":package-srcs",
|
||||
"//pkg/kubectl/cmd/auth:all-srcs",
|
||||
"//pkg/kubectl/cmd/config:all-srcs",
|
||||
"//pkg/kubectl/cmd/resource:all-srcs",
|
||||
"//pkg/kubectl/cmd/create:all-srcs",
|
||||
"//pkg/kubectl/cmd/get:all-srcs",
|
||||
"//pkg/kubectl/cmd/rollout:all-srcs",
|
||||
"//pkg/kubectl/cmd/scalejob:all-srcs",
|
||||
"//pkg/kubectl/cmd/set:all-srcs",
|
||||
"//pkg/kubectl/cmd/templates:all-srcs",
|
||||
"//pkg/kubectl/cmd/testdata/edit:all-srcs",
|
||||
"//pkg/kubectl/cmd/testing:all-srcs",
|
||||
"//pkg/kubectl/cmd/util:all-srcs",
|
||||
"//pkg/kubectl/cmd/wait:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = [
|
||||
|
7
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/alpha.go
generated
vendored
7
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/alpha.go
generated
vendored
@ -17,17 +17,16 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
// NewCmdAlpha creates a command that acts as an alternate root command for features in alpha
|
||||
func NewCmdAlpha(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Command {
|
||||
func NewCmdAlpha(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "alpha",
|
||||
Short: i18n.T("Commands for features in alpha"),
|
||||
@ -37,7 +36,7 @@ func NewCmdAlpha(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Com
|
||||
// Alpha commands should be added here. As features graduate from alpha they should move
|
||||
// from here to the CommandGroups defined by NewKubeletCommand() in cmd.go.
|
||||
//cmd.AddCommand(NewCmdDebug(f, in, out, err))
|
||||
cmd.AddCommand(NewCmdDiff(f, out, err))
|
||||
cmd.AddCommand(NewCmdDiff(f, streams))
|
||||
|
||||
// NewKubeletCommand() will hide the alpha command if it has no subcommands. Overriding
|
||||
// the help function ensures a reasonable message if someone types the hidden command anyway.
|
||||
|
171
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/annotate.go
generated
vendored
171
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/annotate.go
generated
vendored
@ -34,32 +34,44 @@ import (
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
// AnnotateOptions have the data required to perform the annotate operation
|
||||
type AnnotateOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
// Filename options
|
||||
resource.FilenameOptions
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
|
||||
// Common user flags
|
||||
overwrite bool
|
||||
local bool
|
||||
dryrun bool
|
||||
all bool
|
||||
resourceVersion string
|
||||
selector string
|
||||
outputFormat string
|
||||
recordChangeCause bool
|
||||
overwrite bool
|
||||
local bool
|
||||
dryrun bool
|
||||
all bool
|
||||
resourceVersion string
|
||||
selector string
|
||||
fieldSelector string
|
||||
outputFormat string
|
||||
|
||||
// results of arg parsing
|
||||
resources []string
|
||||
newAnnotations map[string]string
|
||||
removeAnnotations []string
|
||||
resources []string
|
||||
newAnnotations map[string]string
|
||||
removeAnnotations []string
|
||||
Recorder genericclioptions.Recorder
|
||||
namespace string
|
||||
enforceNamespace bool
|
||||
builder *resource.Builder
|
||||
unstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
includeUninitialized bool
|
||||
|
||||
// Common share fields
|
||||
out io.Writer
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
@ -69,7 +81,7 @@ var (
|
||||
All Kubernetes objects support the ability to store additional data with the object as
|
||||
annotations. Annotations are key/value pairs that can be larger than labels and include
|
||||
arbitrary string values such as structured JSON. Tools and system extensions may use
|
||||
annotations to store their own data.
|
||||
annotations to store their own data.
|
||||
|
||||
Attempting to set an annotation that already exists will fail unless --overwrite is set.
|
||||
If --resource-version is specified and does not match the current resource version on
|
||||
@ -97,50 +109,81 @@ var (
|
||||
kubectl annotate pods foo description-`))
|
||||
)
|
||||
|
||||
func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := &AnnotateOptions{}
|
||||
validArgs := cmdutil.ValidArgList(f)
|
||||
func NewAnnotateOptions(ioStreams genericclioptions.IOStreams) *AnnotateOptions {
|
||||
return &AnnotateOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("annotated").WithTypeSetter(scheme.Scheme),
|
||||
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdAnnotate(parent string, f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewAnnotateOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "annotate [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version]",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Update the annotations on a resource"),
|
||||
Long: annotateLong + "\n\n" + cmdutil.ValidResourceTypeList(f),
|
||||
Long: annotateLong + "\n\n" + cmdutil.SuggestApiResources(parent),
|
||||
Example: annotateExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if err := options.Complete(out, cmd, args); err != nil {
|
||||
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, "%v", err))
|
||||
}
|
||||
if err := options.Validate(); err != nil {
|
||||
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, "%v", err))
|
||||
}
|
||||
cmdutil.CheckErr(options.RunAnnotate(f, cmd))
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.RunAnnotate())
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
}
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
|
||||
// bind flag structs
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
cmd.Flags().BoolVar(&options.overwrite, "overwrite", options.overwrite, "If true, allow annotations to be overwritten, otherwise reject annotation updates that overwrite existing annotations.")
|
||||
cmd.Flags().BoolVar(&options.local, "local", options.local, "If true, annotation will NOT contact api-server but run locally.")
|
||||
cmd.Flags().StringVarP(&options.selector, "selector", "l", options.selector, "Selector (label query) to filter on, not including uninitialized ones, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2).")
|
||||
cmd.Flags().BoolVar(&options.all, "all", options.all, "Select all resources, including uninitialized ones, in the namespace of the specified resource types.")
|
||||
cmd.Flags().StringVar(&options.resourceVersion, "resource-version", options.resourceVersion, i18n.T("If non-empty, the annotation update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource."))
|
||||
cmd.Flags().BoolVar(&o.overwrite, "overwrite", o.overwrite, "If true, allow annotations to be overwritten, otherwise reject annotation updates that overwrite existing annotations.")
|
||||
cmd.Flags().BoolVar(&o.local, "local", o.local, "If true, annotation will NOT contact api-server but run locally.")
|
||||
cmd.Flags().StringVarP(&o.selector, "selector", "l", o.selector, "Selector (label query) to filter on, not including uninitialized ones, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2).")
|
||||
cmd.Flags().StringVar(&o.fieldSelector, "field-selector", o.fieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.")
|
||||
cmd.Flags().BoolVar(&o.all, "all", o.all, "Select all resources, including uninitialized ones, in the namespace of the specified resource types.")
|
||||
cmd.Flags().StringVar(&o.resourceVersion, "resource-version", o.resourceVersion, i18n.T("If non-empty, the annotation update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource."))
|
||||
usage := "identifying the resource to update the annotation"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Complete adapts from the command line args and factory to the data required.
|
||||
func (o *AnnotateOptions) Complete(out io.Writer, cmd *cobra.Command, args []string) (err error) {
|
||||
o.out = out
|
||||
func (o *AnnotateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
var err error
|
||||
|
||||
o.RecordFlags.Complete(cmd)
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.outputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
o.dryrun = cmdutil.GetDryRunFlag(cmd)
|
||||
o.recordChangeCause = cmdutil.GetRecordFlag(cmd)
|
||||
|
||||
if o.dryrun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.PrintObj = func(obj runtime.Object, out io.Writer) error {
|
||||
return printer.PrintObj(obj, out)
|
||||
}
|
||||
|
||||
o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.includeUninitialized = cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
o.builder = f.NewBuilder()
|
||||
o.unstructuredClientForMapping = f.UnstructuredClientForMapping
|
||||
|
||||
// retrieves resource and annotation args from args
|
||||
// also checks args to verify that all resources are specified before annotations
|
||||
@ -150,7 +193,11 @@ func (o *AnnotateOptions) Complete(out io.Writer, cmd *cobra.Command, args []str
|
||||
}
|
||||
o.resources = resources
|
||||
o.newAnnotations, o.removeAnnotations, err = parseAnnotations(annotationArgs)
|
||||
return err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate checks to the AnnotateOptions to see if there is sufficient information run the command.
|
||||
@ -158,6 +205,9 @@ func (o AnnotateOptions) Validate() error {
|
||||
if o.all && len(o.selector) > 0 {
|
||||
return fmt.Errorf("cannot set --all and --selector at the same time")
|
||||
}
|
||||
if o.all && len(o.fieldSelector) > 0 {
|
||||
return fmt.Errorf("cannot set --all and --field-selector at the same time")
|
||||
}
|
||||
if len(o.resources) < 1 && cmdutil.IsFilenameSliceEmpty(o.Filenames) {
|
||||
return fmt.Errorf("one or more resources must be specified as <resource> <name> or <resource>/<name>")
|
||||
}
|
||||
@ -168,26 +218,19 @@ func (o AnnotateOptions) Validate() error {
|
||||
}
|
||||
|
||||
// RunAnnotate does the work
|
||||
func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
namespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
changeCause := f.Command(cmd, false)
|
||||
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
b := f.NewBuilder().
|
||||
func (o AnnotateOptions) RunAnnotate() error {
|
||||
b := o.builder.
|
||||
Unstructured().
|
||||
LocalParam(o.local).
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
IncludeUninitialized(includeUninitialized).
|
||||
NamespaceParam(o.namespace).DefaultNamespace().
|
||||
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
|
||||
IncludeUninitialized(o.includeUninitialized).
|
||||
Flatten()
|
||||
|
||||
if !o.local {
|
||||
b = b.LabelSelectorParam(o.selector).
|
||||
FieldSelectorParam(o.fieldSelector).
|
||||
ResourceTypeOrNameArgs(o.all, o.resources...).
|
||||
Latest()
|
||||
}
|
||||
@ -214,12 +257,7 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
|
||||
}
|
||||
|
||||
var outputObj runtime.Object
|
||||
var obj runtime.Object
|
||||
|
||||
obj, err = info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj := info.Object
|
||||
|
||||
if o.dryrun || o.local {
|
||||
if err := o.updateAnnotations(obj); err != nil {
|
||||
@ -232,9 +270,8 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// If we should record change-cause, add it to new annotations
|
||||
if cmdutil.ContainsChangeCause(info) || o.recordChangeCause {
|
||||
o.newAnnotations[kubectl.ChangeCauseAnnotation] = changeCause
|
||||
if err := o.Recorder.Record(info.Object); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
if err := o.updateAnnotations(obj); err != nil {
|
||||
return err
|
||||
@ -250,7 +287,7 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
|
||||
}
|
||||
|
||||
mapping := info.ResourceMapping()
|
||||
client, err := f.UnstructuredClientForMapping(mapping)
|
||||
client, err := o.unstructuredClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -266,11 +303,7 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
|
||||
}
|
||||
}
|
||||
|
||||
if len(o.outputFormat) > 0 {
|
||||
return cmdutil.PrintObject(cmd, outputObj, o.out)
|
||||
}
|
||||
cmdutil.PrintSuccess(false, o.out, info.Object, o.dryrun, "annotated")
|
||||
return nil
|
||||
return o.PrintObj(outputObj, o.Out)
|
||||
})
|
||||
}
|
||||
|
||||
|
124
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/annotate_test.go
generated
vendored
124
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/annotate_test.go
generated
vendored
@ -17,7 +17,6 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
@ -30,6 +29,7 @@ import (
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
@ -417,37 +417,45 @@ func TestAnnotateErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
for k, testCase := range testCases {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
t.Run(k, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdAnnotate(tf, buf)
|
||||
cmd.SetOutput(buf)
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
for k, v := range testCase.flags {
|
||||
cmd.Flags().Set(k, v)
|
||||
}
|
||||
options := &AnnotateOptions{}
|
||||
err := options.Complete(buf, cmd, testCase.args)
|
||||
if err == nil {
|
||||
err = options.Validate()
|
||||
}
|
||||
if !testCase.errFn(err) {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
continue
|
||||
}
|
||||
if buf.Len() > 0 {
|
||||
t.Errorf("buffer should be empty: %s", string(buf.Bytes()))
|
||||
}
|
||||
iostreams, _, bufOut, bufErr := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdAnnotate("kubectl", tf, iostreams)
|
||||
cmd.SetOutput(bufOut)
|
||||
|
||||
for k, v := range testCase.flags {
|
||||
cmd.Flags().Set(k, v)
|
||||
}
|
||||
options := NewAnnotateOptions(iostreams)
|
||||
err := options.Complete(tf, cmd, testCase.args)
|
||||
if err == nil {
|
||||
err = options.Validate()
|
||||
}
|
||||
if !testCase.errFn(err) {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
return
|
||||
}
|
||||
if bufOut.Len() > 0 {
|
||||
t.Errorf("buffer should be empty: %s", string(bufOut.Bytes()))
|
||||
}
|
||||
if bufErr.Len() > 0 {
|
||||
t.Errorf("buffer should be empty: %s", string(bufErr.Bytes()))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnnotateObject(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "testgroup", Version: "v1"},
|
||||
@ -476,21 +484,20 @@ func TestAnnotateObject(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdAnnotate(tf, buf)
|
||||
cmd.SetOutput(buf)
|
||||
options := &AnnotateOptions{}
|
||||
iostreams, _, bufOut, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdAnnotate("kubectl", tf, iostreams)
|
||||
cmd.SetOutput(bufOut)
|
||||
options := NewAnnotateOptions(iostreams)
|
||||
args := []string{"pods/foo", "a=b", "c-"}
|
||||
if err := options.Complete(buf, cmd, args); err != nil {
|
||||
if err := options.Complete(tf, cmd, args); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.Validate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.RunAnnotate(tf, cmd); err != nil {
|
||||
if err := options.RunAnnotate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
@ -498,8 +505,10 @@ func TestAnnotateObject(t *testing.T) {
|
||||
func TestAnnotateObjectFromFile(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "testgroup", Version: "v1"},
|
||||
@ -528,28 +537,29 @@ func TestAnnotateObjectFromFile(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdAnnotate(tf, buf)
|
||||
cmd.SetOutput(buf)
|
||||
options := &AnnotateOptions{}
|
||||
iostreams, _, bufOut, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdAnnotate("kubectl", tf, iostreams)
|
||||
cmd.SetOutput(bufOut)
|
||||
options := NewAnnotateOptions(iostreams)
|
||||
options.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
|
||||
args := []string{"a=b", "c-"}
|
||||
if err := options.Complete(buf, cmd, args); err != nil {
|
||||
if err := options.Complete(tf, cmd, args); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.Validate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.RunAnnotate(tf, cmd); err != nil {
|
||||
if err := options.RunAnnotate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnnotateLocal(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "testgroup", Version: "v1"},
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -558,21 +568,21 @@ func TestAnnotateLocal(t *testing.T) {
|
||||
return nil, nil
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdAnnotate(tf, buf)
|
||||
options := &AnnotateOptions{local: true}
|
||||
iostreams, _, _, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdAnnotate("kubectl", tf, iostreams)
|
||||
options := NewAnnotateOptions(iostreams)
|
||||
options.local = true
|
||||
options.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
|
||||
args := []string{"a=b"}
|
||||
if err := options.Complete(buf, cmd, args); err != nil {
|
||||
if err := options.Complete(tf, cmd, args); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.Validate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.RunAnnotate(tf, cmd); err != nil {
|
||||
if err := options.RunAnnotate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
@ -580,8 +590,10 @@ func TestAnnotateLocal(t *testing.T) {
|
||||
func TestAnnotateMultipleObjects(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "testgroup", Version: "v1"},
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -611,21 +623,21 @@ func TestAnnotateMultipleObjects(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdAnnotate(tf, buf)
|
||||
cmd.SetOutput(buf)
|
||||
options := &AnnotateOptions{all: true}
|
||||
iostreams, _, _, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdAnnotate("kubectl", tf, iostreams)
|
||||
cmd.SetOutput(iostreams.Out)
|
||||
options := NewAnnotateOptions(iostreams)
|
||||
options.all = true
|
||||
args := []string{"pods", "a=b", "c-"}
|
||||
if err := options.Complete(buf, cmd, args); err != nil {
|
||||
if err := options.Complete(tf, cmd, args); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.Validate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := options.RunAnnotate(tf, cmd); err != nil {
|
||||
if err := options.RunAnnotate(); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
229
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apiresources.go
generated
vendored
Normal file
229
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apiresources.go
generated
vendored
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
Copyright 2018 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 cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
var (
|
||||
apiresourcesExample = templates.Examples(`
|
||||
# Print the supported API Resources
|
||||
kubectl api-resources
|
||||
|
||||
# Print the supported API Resources with more information
|
||||
kubectl api-resources -o wide
|
||||
|
||||
# Print the supported namespaced resources
|
||||
kubectl api-resources --namespaced=true
|
||||
|
||||
# Print the supported non-namespaced resources
|
||||
kubectl api-resources --namespaced=false
|
||||
|
||||
# Print the supported API Resources with specific APIGroup
|
||||
kubectl api-resources --api-group=extensions`)
|
||||
)
|
||||
|
||||
// ApiResourcesOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
|
||||
// referencing the cmd.Flags()
|
||||
type ApiResourcesOptions struct {
|
||||
Output string
|
||||
APIGroup string
|
||||
Namespaced bool
|
||||
Verbs []string
|
||||
NoHeaders bool
|
||||
Cached bool
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
// groupResource contains the APIGroup and APIResource
|
||||
type groupResource struct {
|
||||
APIGroup string
|
||||
APIResource metav1.APIResource
|
||||
}
|
||||
|
||||
func NewAPIResourceOptions(ioStreams genericclioptions.IOStreams) *ApiResourcesOptions {
|
||||
return &ApiResourcesOptions{
|
||||
IOStreams: ioStreams,
|
||||
Namespaced: true,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdApiResources(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewAPIResourceOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "api-resources",
|
||||
Short: "Print the supported API resources on the server",
|
||||
Long: "Print the supported API resources on the server",
|
||||
Example: apiresourcesExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Validate(cmd))
|
||||
cmdutil.CheckErr(o.RunApiResources(cmd, f))
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().BoolVar(&o.NoHeaders, "no-headers", o.NoHeaders, "When using the default or custom-column output format, don't print headers (default print headers).")
|
||||
cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, "Output format. One of: wide|name.")
|
||||
|
||||
cmd.Flags().StringVar(&o.APIGroup, "api-group", o.APIGroup, "Limit to resources in the specified API group.")
|
||||
cmd.Flags().BoolVar(&o.Namespaced, "namespaced", o.Namespaced, "If false, non-namespaced resources will be returned, otherwise returning namespaced resources by default.")
|
||||
cmd.Flags().StringSliceVar(&o.Verbs, "verbs", o.Verbs, "Limit to resources that support the specified verbs.")
|
||||
cmd.Flags().BoolVar(&o.Cached, "cached", o.Cached, "Use the cached list of resources if available.")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *ApiResourcesOptions) Validate(cmd *cobra.Command) error {
|
||||
supportedOutputTypes := sets.NewString("", "wide", "name")
|
||||
if !supportedOutputTypes.Has(o.Output) {
|
||||
return fmt.Errorf("--output %v is not available", o.Output)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ApiResourcesOptions) RunApiResources(cmd *cobra.Command, f cmdutil.Factory) error {
|
||||
w := printers.GetNewTabWriter(o.Out)
|
||||
defer w.Flush()
|
||||
|
||||
discoveryclient, err := f.ToDiscoveryClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !o.Cached {
|
||||
// Always request fresh data from the server
|
||||
discoveryclient.Invalidate()
|
||||
}
|
||||
|
||||
lists, err := discoveryclient.ServerPreferredResources()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resources := []groupResource{}
|
||||
|
||||
groupChanged := cmd.Flags().Changed("api-group")
|
||||
nsChanged := cmd.Flags().Changed("namespaced")
|
||||
|
||||
for _, list := range lists {
|
||||
if len(list.APIResources) == 0 {
|
||||
continue
|
||||
}
|
||||
gv, err := schema.ParseGroupVersion(list.GroupVersion)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, resource := range list.APIResources {
|
||||
if len(resource.Verbs) == 0 {
|
||||
continue
|
||||
}
|
||||
// filter apiGroup
|
||||
if groupChanged && o.APIGroup != gv.Group {
|
||||
continue
|
||||
}
|
||||
// filter namespaced
|
||||
if nsChanged && o.Namespaced != resource.Namespaced {
|
||||
continue
|
||||
}
|
||||
// filter to resources that support the specified verbs
|
||||
if len(o.Verbs) > 0 && !sets.NewString(resource.Verbs...).HasAll(o.Verbs...) {
|
||||
continue
|
||||
}
|
||||
resources = append(resources, groupResource{
|
||||
APIGroup: gv.Group,
|
||||
APIResource: resource,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if o.NoHeaders == false && o.Output != "name" {
|
||||
if err = printContextHeaders(w, o.Output); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
sort.Stable(sortableGroupResource(resources))
|
||||
for _, r := range resources {
|
||||
switch o.Output {
|
||||
case "name":
|
||||
name := r.APIResource.Name
|
||||
if len(r.APIGroup) > 0 {
|
||||
name += "." + r.APIGroup
|
||||
}
|
||||
if _, err := fmt.Fprintf(w, "%s\n", name); err != nil {
|
||||
return err
|
||||
}
|
||||
case "wide":
|
||||
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%v\t%s\t%v\n",
|
||||
r.APIResource.Name,
|
||||
strings.Join(r.APIResource.ShortNames, ","),
|
||||
r.APIGroup,
|
||||
r.APIResource.Namespaced,
|
||||
r.APIResource.Kind,
|
||||
r.APIResource.Verbs); err != nil {
|
||||
return err
|
||||
}
|
||||
case "":
|
||||
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%v\t%s\n",
|
||||
r.APIResource.Name,
|
||||
strings.Join(r.APIResource.ShortNames, ","),
|
||||
r.APIGroup,
|
||||
r.APIResource.Namespaced,
|
||||
r.APIResource.Kind); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func printContextHeaders(out io.Writer, output string) error {
|
||||
columnNames := []string{"NAME", "SHORTNAMES", "APIGROUP", "NAMESPACED", "KIND"}
|
||||
if output == "wide" {
|
||||
columnNames = append(columnNames, "VERBS")
|
||||
}
|
||||
_, err := fmt.Fprintf(out, "%s\n", strings.Join(columnNames, "\t"))
|
||||
return err
|
||||
}
|
||||
|
||||
type sortableGroupResource []groupResource
|
||||
|
||||
func (s sortableGroupResource) Len() int { return len(s) }
|
||||
func (s sortableGroupResource) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s sortableGroupResource) Less(i, j int) bool {
|
||||
ret := strings.Compare(s[i].APIGroup, s[j].APIGroup)
|
||||
if ret > 0 {
|
||||
return false
|
||||
} else if ret == 0 {
|
||||
return strings.Compare(s[i].APIResource.Name, s[j].APIResource.Name) < 0
|
||||
}
|
||||
return true
|
||||
}
|
36
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apiversions.go
generated
vendored
36
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apiversions.go
generated
vendored
@ -18,14 +18,15 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -35,37 +36,54 @@ var (
|
||||
kubectl api-versions`))
|
||||
)
|
||||
|
||||
func NewCmdApiVersions(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
type ApiVersionsOptions struct {
|
||||
discoveryClient discovery.CachedDiscoveryInterface
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewApiVersionsOptions(ioStreams genericclioptions.IOStreams) *ApiVersionsOptions {
|
||||
return &ApiVersionsOptions{
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdApiVersions(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewApiVersionsOptions(ioStreams)
|
||||
cmd := &cobra.Command{
|
||||
Use: "api-versions",
|
||||
Short: "Print the supported API versions on the server, in the form of \"group/version\"",
|
||||
Long: "Print the supported API versions on the server, in the form of \"group/version\"",
|
||||
Example: apiversionsExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := RunApiVersions(f, out)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(o.Complete(f))
|
||||
cmdutil.CheckErr(o.RunApiVersions())
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunApiVersions(f cmdutil.Factory, w io.Writer) error {
|
||||
discoveryclient, err := f.DiscoveryClient()
|
||||
func (o *ApiVersionsOptions) Complete(f cmdutil.Factory) error {
|
||||
var err error
|
||||
o.discoveryClient, err = f.ToDiscoveryClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ApiVersionsOptions) RunApiVersions() error {
|
||||
// Always request fresh data from the server
|
||||
discoveryclient.Invalidate()
|
||||
o.discoveryClient.Invalidate()
|
||||
|
||||
groupList, err := discoveryclient.ServerGroups()
|
||||
groupList, err := o.discoveryClient.ServerGroups()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Couldn't get available api versions from server: %v\n", err)
|
||||
}
|
||||
apiVersions := metav1.ExtractGroupVersions(groupList)
|
||||
sort.Strings(apiVersions)
|
||||
for _, v := range apiVersions {
|
||||
fmt.Fprintln(w, v)
|
||||
fmt.Fprintln(o.Out, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
478
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply.go
generated
vendored
478
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply.go
generated
vendored
@ -26,9 +26,11 @@ import (
|
||||
"github.com/jonboulle/clockwork"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@ -37,29 +39,52 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/dynamic"
|
||||
oapi "k8s.io/kube-openapi/pkg/util/proto"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/kubectl/validation"
|
||||
)
|
||||
|
||||
type ApplyOptions struct {
|
||||
FilenameOptions resource.FilenameOptions
|
||||
Selector string
|
||||
Force bool
|
||||
Prune bool
|
||||
Cascade bool
|
||||
GracePeriod int
|
||||
PruneResources []pruneResource
|
||||
Timeout time.Duration
|
||||
cmdBaseName string
|
||||
all bool
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
Recorder genericclioptions.Recorder
|
||||
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
ToPrinter func(string) (printers.ResourcePrinter, error)
|
||||
|
||||
DeleteFlags *DeleteFlags
|
||||
DeleteOptions *DeleteOptions
|
||||
|
||||
Selector string
|
||||
DryRun bool
|
||||
Prune bool
|
||||
PruneResources []pruneResource
|
||||
cmdBaseName string
|
||||
All bool
|
||||
Overwrite bool
|
||||
OpenApiPatch bool
|
||||
PruneWhitelist []string
|
||||
ShouldIncludeUninitialized bool
|
||||
|
||||
Validator validation.Schema
|
||||
Builder *resource.Builder
|
||||
Mapper meta.RESTMapper
|
||||
DynamicClient dynamic.Interface
|
||||
OpenAPISchema openapi.Resources
|
||||
|
||||
Namespace string
|
||||
EnforceNamespace bool
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
const (
|
||||
@ -98,12 +123,27 @@ var (
|
||||
warningNoLastAppliedConfigAnnotation = "Warning: %[1]s apply should be used on resource created by either %[1]s create --save-config or %[1]s apply\n"
|
||||
)
|
||||
|
||||
func NewCmdApply(baseName string, f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
var options ApplyOptions
|
||||
func NewApplyOptions(ioStreams genericclioptions.IOStreams) *ApplyOptions {
|
||||
return &ApplyOptions{
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
DeleteFlags: NewDeleteFlags("that contains the configuration to apply"),
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
|
||||
|
||||
Overwrite: true,
|
||||
OpenApiPatch: true,
|
||||
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdApply(baseName string, f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewApplyOptions(ioStreams)
|
||||
|
||||
// Store baseName for use in printing warnings / messages involving the base command name.
|
||||
// This is useful for downstream command that wrap this one.
|
||||
options.cmdBaseName = baseName
|
||||
o.cmdBaseName = baseName
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "apply -f FILENAME",
|
||||
@ -112,40 +152,85 @@ func NewCmdApply(baseName string, f cmdutil.Factory, out, errOut io.Writer) *cob
|
||||
Long: applyLong,
|
||||
Example: applyExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(validateArgs(cmd, args))
|
||||
cmdutil.CheckErr(validatePruneAll(options.Prune, options.all, options.Selector))
|
||||
cmdutil.CheckErr(RunApply(f, cmd, out, errOut, &options))
|
||||
cmdutil.CheckErr(validatePruneAll(o.Prune, o.All, o.Selector))
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
}
|
||||
|
||||
usage := "that contains the configuration to apply"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
// bind flag structs
|
||||
o.DeleteFlags.AddFlags(cmd)
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmd.MarkFlagRequired("filename")
|
||||
cmd.Flags().Bool("overwrite", true, "Automatically resolve conflicts between the modified and live configuration by using values from the modified configuration")
|
||||
cmd.Flags().BoolVar(&options.Prune, "prune", false, "Automatically delete resource objects, including the uninitialized ones, that do not appear in the configs and are created by either apply or create --save-config. Should be used with either -l or --all.")
|
||||
cmd.Flags().BoolVar(&options.Cascade, "cascade", true, "Only relevant during a prune or a force apply. If true, cascade the deletion of the resources managed by pruned or deleted resources (e.g. Pods created by a ReplicationController).")
|
||||
cmd.Flags().IntVar(&options.GracePeriod, "grace-period", -1, "Only relevant during a prune or a force apply. Period of time in seconds given to pruned or deleted resources to terminate gracefully. Ignored if negative.")
|
||||
cmd.Flags().BoolVar(&options.Force, "force", false, fmt.Sprintf("Delete and re-create the specified resource, when PATCH encounters conflict and has retried for %d times.", maxPatchRetry))
|
||||
cmd.Flags().DurationVar(&options.Timeout, "timeout", 0, "Only relevant during a force apply. The length of time to wait before giving up on a delete of the old resource, zero means determine a timeout from the size of the object. Any other values should contain a corresponding time unit (e.g. 1s, 2m, 3h).")
|
||||
cmd.Flags().BoolVar(&o.Overwrite, "overwrite", o.Overwrite, "Automatically resolve conflicts between the modified and live configuration by using values from the modified configuration")
|
||||
cmd.Flags().BoolVar(&o.Prune, "prune", o.Prune, "Automatically delete resource objects, including the uninitialized ones, that do not appear in the configs and are created by either apply or create --save-config. Should be used with either -l or --all.")
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().BoolVar(&options.all, "all", options.all, "Select all resources in the namespace of the specified resource types.")
|
||||
cmd.Flags().StringArray("prune-whitelist", []string{}, "Overwrite the default whitelist with <group/version/kind> for --prune")
|
||||
cmd.Flags().Bool("openapi-patch", true, "If true, use openapi to calculate diff when the openapi presents and the resource can be found in the openapi spec. Otherwise, fall back to use baked-in types.")
|
||||
cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().BoolVar(&o.All, "all", o.All, "Select all resources in the namespace of the specified resource types.")
|
||||
cmd.Flags().StringArrayVar(&o.PruneWhitelist, "prune-whitelist", o.PruneWhitelist, "Overwrite the default whitelist with <group/version/kind> for --prune")
|
||||
cmd.Flags().BoolVar(&o.OpenApiPatch, "openapi-patch", o.OpenApiPatch, "If true, use openapi to calculate diff when the openapi presents and the resource can be found in the openapi spec. Otherwise, fall back to use baked-in types.")
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
|
||||
// apply subcommands
|
||||
cmd.AddCommand(NewCmdApplyViewLastApplied(f, out, errOut))
|
||||
cmd.AddCommand(NewCmdApplySetLastApplied(f, out, errOut))
|
||||
cmd.AddCommand(NewCmdApplyEditLastApplied(f, out, errOut))
|
||||
cmd.AddCommand(NewCmdApplyViewLastApplied(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdApplySetLastApplied(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdApplyEditLastApplied(f, ioStreams))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
|
||||
// allow for a success message operation to be specified at print time
|
||||
o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) {
|
||||
o.PrintFlags.NamePrintFlags.Operation = operation
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
|
||||
return o.PrintFlags.ToPrinter()
|
||||
}
|
||||
|
||||
var err error
|
||||
o.RecordFlags.Complete(cmd)
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dynamicClient, err := f.DynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.DeleteOptions = o.DeleteFlags.ToOptions(dynamicClient, o.IOStreams)
|
||||
o.ShouldIncludeUninitialized = cmdutil.ShouldIncludeUninitialized(cmd, o.Prune)
|
||||
|
||||
o.OpenAPISchema, _ = f.OpenAPISchema()
|
||||
o.Validator, err = f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
|
||||
o.Builder = f.NewBuilder()
|
||||
o.Mapper, err = f.ToRESTMapper()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.DynamicClient, err = f.DynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateArgs(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
|
||||
@ -194,60 +279,44 @@ func parsePruneResources(mapper meta.RESTMapper, gvks []string) ([]pruneResource
|
||||
return pruneResources, nil
|
||||
}
|
||||
|
||||
func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, options *ApplyOptions) error {
|
||||
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *ApplyOptions) Run() error {
|
||||
var openapiSchema openapi.Resources
|
||||
if cmdutil.GetFlagBool(cmd, "openapi-patch") {
|
||||
openapiSchema, err = f.OpenAPISchema()
|
||||
if err != nil {
|
||||
openapiSchema = nil
|
||||
}
|
||||
}
|
||||
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
if o.OpenApiPatch {
|
||||
openapiSchema = o.OpenAPISchema
|
||||
}
|
||||
|
||||
// include the uninitialized objects by default if --prune is true
|
||||
// unless explicitly set --include-uninitialized=false
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, options.Prune)
|
||||
r := f.NewBuilder().
|
||||
r := o.Builder.
|
||||
Unstructured().
|
||||
Schema(schema).
|
||||
Schema(o.Validator).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &options.FilenameOptions).
|
||||
LabelSelectorParam(options.Selector).
|
||||
IncludeUninitialized(includeUninitialized).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
FilenameParam(o.EnforceNamespace, &o.DeleteOptions.FilenameOptions).
|
||||
LabelSelectorParam(o.Selector).
|
||||
IncludeUninitialized(o.ShouldIncludeUninitialized).
|
||||
Flatten().
|
||||
Do()
|
||||
if err := r.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if options.Prune {
|
||||
options.PruneResources, err = parsePruneResources(r.Mapper().RESTMapper, cmdutil.GetFlagStringArray(cmd, "prune-whitelist"))
|
||||
var err error
|
||||
if o.Prune {
|
||||
o.PruneResources, err = parsePruneResources(o.Mapper, o.PruneWhitelist)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
dryRun := cmdutil.GetDryRunFlag(cmd)
|
||||
output := cmdutil.GetFlagString(cmd, "output")
|
||||
output := *o.PrintFlags.OutputFormat
|
||||
shortOutput := output == "name"
|
||||
|
||||
encoder := scheme.DefaultJSONEncoder()
|
||||
deserializer := scheme.Codecs.UniversalDeserializer()
|
||||
mapper := r.Mapper().RESTMapper
|
||||
|
||||
visitedUids := sets.NewString()
|
||||
visitedNamespaces := sets.NewString()
|
||||
|
||||
var objs []runtime.Object
|
||||
|
||||
count := 0
|
||||
err = r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
@ -258,145 +327,185 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti
|
||||
visitedNamespaces.Insert(info.Namespace)
|
||||
}
|
||||
|
||||
// Add change-cause annotation to resource info if it should be recorded
|
||||
if cmdutil.ShouldRecord(cmd, info) {
|
||||
recordInObj := info.Object
|
||||
if err := cmdutil.RecordChangeCause(recordInObj, f.Command(cmd, false)); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
if err := o.Recorder.Record(info.Object); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
|
||||
// Get the modified configuration of the object. Embed the result
|
||||
// as an annotation in the modified configuration, so that it will appear
|
||||
// in the patch sent to the server.
|
||||
modified, err := kubectl.GetModifiedConfiguration(info, true, encoder)
|
||||
modified, err := kubectl.GetModifiedConfiguration(info.Object, true, unstructured.UnstructuredJSONScheme)
|
||||
if err != nil {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving modified configuration from:\n%v\nfor:", info), info.Source, err)
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving modified configuration from:\n%s\nfor:", info.String()), info.Source, err)
|
||||
}
|
||||
|
||||
// Print object only if output format other than "name" is specified
|
||||
printObject := len(output) > 0 && !shortOutput
|
||||
|
||||
if err := info.Get(); err != nil {
|
||||
if !errors.IsNotFound(err) {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%v\nfrom server for:", info), info.Source, err)
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%s\nfrom server for:", info.String()), info.Source, err)
|
||||
}
|
||||
// Create the resource if it doesn't exist
|
||||
// First, update the annotation used by kubectl apply
|
||||
if err := kubectl.CreateApplyAnnotation(info, encoder); err != nil {
|
||||
if err := kubectl.CreateApplyAnnotation(info.Object, unstructured.UnstructuredJSONScheme); err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
|
||||
if !dryRun {
|
||||
if !o.DryRun {
|
||||
// Then create the resource and skip the three-way merge
|
||||
if err := createAndRefresh(info); err != nil {
|
||||
obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
|
||||
if err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
if uid, err := info.Mapping.UID(info.Object); err != nil {
|
||||
info.Refresh(obj, true)
|
||||
metadata, err := meta.Accessor(info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
visitedUids.Insert(string(uid))
|
||||
}
|
||||
visitedUids.Insert(string(metadata.GetUID()))
|
||||
}
|
||||
|
||||
count++
|
||||
if len(output) > 0 && !shortOutput {
|
||||
return cmdutil.PrintObject(cmd, info.Object, out)
|
||||
}
|
||||
cmdutil.PrintSuccess(shortOutput, out, info.Object, dryRun, "created")
|
||||
return nil
|
||||
}
|
||||
|
||||
if !dryRun {
|
||||
annotationMap, err := info.Mapping.MetadataAccessor.Annotations(info.Object)
|
||||
if printObject {
|
||||
objs = append(objs, info.Object)
|
||||
return nil
|
||||
}
|
||||
|
||||
printer, err := o.ToPrinter("created")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := annotationMap[api.LastAppliedConfigAnnotation]; !ok {
|
||||
fmt.Fprintf(errOut, warningNoLastAppliedConfigAnnotation, options.cmdBaseName)
|
||||
return printer.PrintObj(info.Object, o.Out)
|
||||
}
|
||||
|
||||
if !o.DryRun {
|
||||
metadata, err := meta.Accessor(info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
overwrite := cmdutil.GetFlagBool(cmd, "overwrite")
|
||||
|
||||
annotationMap := metadata.GetAnnotations()
|
||||
if _, ok := annotationMap[api.LastAppliedConfigAnnotation]; !ok {
|
||||
fmt.Fprintf(o.ErrOut, warningNoLastAppliedConfigAnnotation, o.cmdBaseName)
|
||||
}
|
||||
|
||||
helper := resource.NewHelper(info.Client, info.Mapping)
|
||||
patcher := &patcher{
|
||||
encoder: encoder,
|
||||
decoder: deserializer,
|
||||
mapping: info.Mapping,
|
||||
helper: helper,
|
||||
clientFunc: f.UnstructuredClientForMapping,
|
||||
clientsetFunc: f.ClientSet,
|
||||
overwrite: overwrite,
|
||||
dynamicClient: o.DynamicClient,
|
||||
overwrite: o.Overwrite,
|
||||
backOff: clockwork.NewRealClock(),
|
||||
force: options.Force,
|
||||
cascade: options.Cascade,
|
||||
timeout: options.Timeout,
|
||||
gracePeriod: options.GracePeriod,
|
||||
force: o.DeleteOptions.ForceDeletion,
|
||||
cascade: o.DeleteOptions.Cascade,
|
||||
timeout: o.DeleteOptions.Timeout,
|
||||
gracePeriod: o.DeleteOptions.GracePeriod,
|
||||
openapiSchema: openapiSchema,
|
||||
}
|
||||
|
||||
patchBytes, patchedObject, err := patcher.patch(info.Object, modified, info.Source, info.Namespace, info.Name, errOut)
|
||||
patchBytes, patchedObject, err := patcher.patch(info.Object, modified, info.Source, info.Namespace, info.Name, o.ErrOut)
|
||||
if err != nil {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("applying patch:\n%s\nto:\n%v\nfor:", patchBytes, info), info.Source, err)
|
||||
}
|
||||
|
||||
info.Refresh(patchedObject, true)
|
||||
|
||||
if uid, err := info.Mapping.UID(info.Object); err != nil {
|
||||
return err
|
||||
} else {
|
||||
visitedUids.Insert(string(uid))
|
||||
}
|
||||
visitedUids.Insert(string(metadata.GetUID()))
|
||||
|
||||
if string(patchBytes) == "{}" {
|
||||
if string(patchBytes) == "{}" && !printObject {
|
||||
count++
|
||||
cmdutil.PrintSuccess(shortOutput, out, info.Object, false, "unchanged")
|
||||
return nil
|
||||
|
||||
printer, err := o.ToPrinter("unchanged")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printer.PrintObj(info.Object, o.Out)
|
||||
}
|
||||
}
|
||||
count++
|
||||
if len(output) > 0 && !shortOutput {
|
||||
return cmdutil.PrintObject(cmd, info.Object, out)
|
||||
}
|
||||
cmdutil.PrintSuccess(shortOutput, out, info.Object, dryRun, "configured")
|
||||
return nil
|
||||
})
|
||||
|
||||
if printObject {
|
||||
objs = append(objs, info.Object)
|
||||
return nil
|
||||
}
|
||||
|
||||
printer, err := o.ToPrinter("configured")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printer.PrintObj(info.Object, o.Out)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return fmt.Errorf("no objects passed to apply")
|
||||
}
|
||||
|
||||
if !options.Prune {
|
||||
// print objects
|
||||
if len(objs) > 0 {
|
||||
printer, err := o.ToPrinter("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
objToPrint := objs[0]
|
||||
if len(objs) > 1 {
|
||||
list := &v1.List{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "List",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ListMeta: metav1.ListMeta{},
|
||||
}
|
||||
if err := meta.SetList(list, objs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
objToPrint = list
|
||||
}
|
||||
if err := printer.PrintObj(objToPrint, o.Out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !o.Prune {
|
||||
return nil
|
||||
}
|
||||
|
||||
p := pruner{
|
||||
mapper: mapper,
|
||||
clientFunc: f.UnstructuredClientForMapping,
|
||||
clientsetFunc: f.ClientSet,
|
||||
mapper: o.Mapper,
|
||||
dynamicClient: o.DynamicClient,
|
||||
|
||||
labelSelector: options.Selector,
|
||||
labelSelector: o.Selector,
|
||||
visitedUids: visitedUids,
|
||||
|
||||
cascade: options.Cascade,
|
||||
dryRun: dryRun,
|
||||
gracePeriod: options.GracePeriod,
|
||||
cascade: o.DeleteOptions.Cascade,
|
||||
dryRun: o.DryRun,
|
||||
gracePeriod: o.DeleteOptions.GracePeriod,
|
||||
|
||||
out: out,
|
||||
toPrinter: o.ToPrinter,
|
||||
|
||||
out: o.Out,
|
||||
}
|
||||
|
||||
namespacedRESTMappings, nonNamespacedRESTMappings, err := getRESTMappings(mapper, &(options.PruneResources))
|
||||
namespacedRESTMappings, nonNamespacedRESTMappings, err := getRESTMappings(o.Mapper, &(o.PruneResources))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error retrieving RESTMappings to prune: %v", err)
|
||||
}
|
||||
|
||||
for n := range visitedNamespaces {
|
||||
for _, m := range namespacedRESTMappings {
|
||||
if err := p.prune(f, n, m, shortOutput, includeUninitialized); err != nil {
|
||||
if err := p.prune(n, m, o.ShouldIncludeUninitialized); err != nil {
|
||||
return fmt.Errorf("error pruning namespaced object %v: %v", m.GroupVersionKind, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, m := range nonNamespacedRESTMappings {
|
||||
if err := p.prune(f, metav1.NamespaceNone, m, shortOutput, includeUninitialized); err != nil {
|
||||
if err := p.prune(metav1.NamespaceNone, m, o.ShouldIncludeUninitialized); err != nil {
|
||||
return fmt.Errorf("error pruning nonNamespaced object %v: %v", m.GroupVersionKind, err)
|
||||
}
|
||||
}
|
||||
@ -430,6 +539,7 @@ func getRESTMappings(mapper meta.RESTMapper, pruneResources *[]pruneResource) (n
|
||||
{"", "v1", "Secret", true},
|
||||
{"", "v1", "Service", true},
|
||||
{"batch", "v1", "Job", true},
|
||||
{"batch", "v1beta1", "CronJob", true},
|
||||
{"extensions", "v1beta1", "DaemonSet", true},
|
||||
{"extensions", "v1beta1", "Deployment", true},
|
||||
{"extensions", "v1beta1", "Ingress", true},
|
||||
@ -456,8 +566,7 @@ func getRESTMappings(mapper meta.RESTMapper, pruneResources *[]pruneResource) (n
|
||||
|
||||
type pruner struct {
|
||||
mapper meta.RESTMapper
|
||||
clientFunc resource.ClientMapperFunc
|
||||
clientsetFunc func() (internalclientset.Interface, error)
|
||||
dynamicClient dynamic.Interface
|
||||
|
||||
visitedUids sets.String
|
||||
labelSelector string
|
||||
@ -467,117 +576,83 @@ type pruner struct {
|
||||
dryRun bool
|
||||
gracePeriod int
|
||||
|
||||
toPrinter func(string) (printers.ResourcePrinter, error)
|
||||
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
func (p *pruner) prune(f cmdutil.Factory, namespace string, mapping *meta.RESTMapping, shortOutput, includeUninitialized bool) error {
|
||||
c, err := p.clientFunc(mapping)
|
||||
func (p *pruner) prune(namespace string, mapping *meta.RESTMapping, includeUninitialized bool) error {
|
||||
objList, err := p.dynamicClient.Resource(mapping.Resource).
|
||||
Namespace(namespace).
|
||||
List(metav1.ListOptions{
|
||||
LabelSelector: p.labelSelector,
|
||||
FieldSelector: p.fieldSelector,
|
||||
IncludeUninitialized: includeUninitialized,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
objList, err := resource.NewHelper(c, mapping).List(
|
||||
namespace,
|
||||
mapping.GroupVersionKind.Version,
|
||||
false,
|
||||
&metav1.ListOptions{
|
||||
LabelSelector: p.labelSelector,
|
||||
FieldSelector: p.fieldSelector,
|
||||
IncludeUninitialized: includeUninitialized,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
objs, err := meta.ExtractList(objList)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, obj := range objs {
|
||||
annots, err := mapping.MetadataAccessor.Annotations(obj)
|
||||
metadata, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
annots := metadata.GetAnnotations()
|
||||
if _, ok := annots[api.LastAppliedConfigAnnotation]; !ok {
|
||||
// don't prune resources not created with apply
|
||||
continue
|
||||
}
|
||||
uid, err := mapping.UID(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
uid := metadata.GetUID()
|
||||
if p.visitedUids.Has(string(uid)) {
|
||||
continue
|
||||
}
|
||||
|
||||
name, err := mapping.Name(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := metadata.GetName()
|
||||
if !p.dryRun {
|
||||
if err := p.delete(namespace, name, mapping); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
cmdutil.PrintSuccess(shortOutput, p.out, obj, p.dryRun, "pruned")
|
||||
|
||||
printer, err := p.toPrinter("pruned")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printer.PrintObj(obj, p.out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping) error {
|
||||
c, err := p.clientFunc(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return runDelete(namespace, name, mapping, c, nil, p.cascade, p.gracePeriod, p.clientsetFunc)
|
||||
return runDelete(namespace, name, mapping, p.dynamicClient, p.cascade, p.gracePeriod)
|
||||
}
|
||||
|
||||
func runDelete(namespace, name string, mapping *meta.RESTMapping, c resource.RESTClient, helper *resource.Helper, cascade bool, gracePeriod int, clientsetFunc func() (internalclientset.Interface, error)) error {
|
||||
if !cascade {
|
||||
if helper == nil {
|
||||
helper = resource.NewHelper(c, mapping)
|
||||
}
|
||||
return helper.Delete(namespace, name)
|
||||
}
|
||||
cs, err := clientsetFunc()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r, err := kubectl.ReaperFor(mapping.GroupVersionKind.GroupKind(), cs)
|
||||
if err != nil {
|
||||
if _, ok := err.(*kubectl.NoSuchReaperError); !ok {
|
||||
return err
|
||||
}
|
||||
return resource.NewHelper(c, mapping).Delete(namespace, name)
|
||||
}
|
||||
var options *metav1.DeleteOptions
|
||||
func runDelete(namespace, name string, mapping *meta.RESTMapping, c dynamic.Interface, cascade bool, gracePeriod int) error {
|
||||
options := &metav1.DeleteOptions{}
|
||||
if gracePeriod >= 0 {
|
||||
options = metav1.NewDeleteOptions(int64(gracePeriod))
|
||||
}
|
||||
if err := r.Stop(namespace, name, 2*time.Minute, options); err != nil {
|
||||
return err
|
||||
policy := metav1.DeletePropagationForeground
|
||||
if !cascade {
|
||||
policy = metav1.DeletePropagationOrphan
|
||||
}
|
||||
return nil
|
||||
options.PropagationPolicy = &policy
|
||||
return c.Resource(mapping.Resource).Namespace(namespace).Delete(name, options)
|
||||
}
|
||||
|
||||
func (p *patcher) delete(namespace, name string) error {
|
||||
c, err := p.clientFunc(p.mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runDelete(namespace, name, p.mapping, c, p.helper, p.cascade, p.gracePeriod, p.clientsetFunc)
|
||||
return runDelete(namespace, name, p.mapping, p.dynamicClient, p.cascade, p.gracePeriod)
|
||||
}
|
||||
|
||||
type patcher struct {
|
||||
encoder runtime.Encoder
|
||||
decoder runtime.Decoder
|
||||
|
||||
mapping *meta.RESTMapping
|
||||
helper *resource.Helper
|
||||
clientFunc resource.ClientMapperFunc
|
||||
clientsetFunc func() (internalclientset.Interface, error)
|
||||
dynamicClient dynamic.Interface
|
||||
|
||||
overwrite bool
|
||||
backOff clockwork.Clock
|
||||
@ -592,13 +667,13 @@ type patcher struct {
|
||||
|
||||
func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, namespace, name string, errOut io.Writer) ([]byte, runtime.Object, error) {
|
||||
// Serialize the current configuration of the object from the server.
|
||||
current, err := runtime.Encode(p.encoder, obj)
|
||||
current, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
|
||||
if err != nil {
|
||||
return nil, nil, cmdutil.AddSourceToErr(fmt.Sprintf("serializing current configuration from:\n%v\nfor:", obj), source, err)
|
||||
}
|
||||
|
||||
// Retrieve the original configuration of the object from the annotation.
|
||||
original, err := kubectl.GetOriginalConfiguration(p.mapping, obj)
|
||||
original, err := kubectl.GetOriginalConfiguration(obj)
|
||||
if err != nil {
|
||||
return nil, nil, cmdutil.AddSourceToErr(fmt.Sprintf("retrieving original configuration from:\n%v\nfor:", obj), source, err)
|
||||
}
|
||||
@ -685,20 +760,19 @@ func (p *patcher) patch(current runtime.Object, modified []byte, source, namespa
|
||||
}
|
||||
|
||||
func (p *patcher) deleteAndCreate(original runtime.Object, modified []byte, namespace, name string) ([]byte, runtime.Object, error) {
|
||||
err := p.delete(namespace, name)
|
||||
if err != nil {
|
||||
if err := p.delete(namespace, name); err != nil {
|
||||
return modified, nil, err
|
||||
}
|
||||
err = wait.PollImmediate(kubectl.Interval, p.timeout, func() (bool, error) {
|
||||
// TODO: use wait
|
||||
if err := wait.PollImmediate(1*time.Second, p.timeout, func() (bool, error) {
|
||||
if _, err := p.helper.Get(namespace, name, false); !errors.IsNotFound(err) {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
if err != nil {
|
||||
}); err != nil {
|
||||
return modified, nil, err
|
||||
}
|
||||
versionedObject, _, err := p.decoder.Decode(modified, nil, nil)
|
||||
versionedObject, _, err := unstructured.UnstructuredJSONScheme.Decode(modified, nil, nil)
|
||||
if err != nil {
|
||||
return modified, nil, err
|
||||
}
|
||||
|
29
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_edit_last_applied.go
generated
vendored
29
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_edit_last_applied.go
generated
vendored
@ -17,15 +17,12 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -58,11 +55,8 @@ var (
|
||||
kubectl apply edit-last-applied -f deploy.yaml -o json`)
|
||||
)
|
||||
|
||||
func NewCmdApplyEditLastApplied(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
options := &editor.EditOptions{
|
||||
EditMode: editor.ApplyEditMode,
|
||||
}
|
||||
validArgs := cmdutil.ValidArgList(f)
|
||||
func NewCmdApplyEditLastApplied(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := editor.NewEditOptions(editor.ApplyEditMode, ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "edit-last-applied (RESOURCE/NAME | -f FILENAME)",
|
||||
@ -71,24 +65,23 @@ func NewCmdApplyEditLastApplied(f cmdutil.Factory, out, errOut io.Writer) *cobra
|
||||
Long: applyEditLastAppliedLong,
|
||||
Example: applyEditLastAppliedExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
options.ChangeCause = f.Command(cmd, false)
|
||||
if err := options.Complete(f, out, errOut, args, cmd); err != nil {
|
||||
if err := o.Complete(f, args, cmd); err != nil {
|
||||
cmdutil.CheckErr(err)
|
||||
}
|
||||
if err := options.Run(); err != nil {
|
||||
if err := o.Run(); err != nil {
|
||||
cmdutil.CheckErr(err)
|
||||
}
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
}
|
||||
|
||||
// bind flag structs
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
|
||||
usage := "to use to edit the resource"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmd.Flags().StringVarP(&options.Output, "output", "o", "yaml", "Output format. One of: yaml|json.")
|
||||
cmd.Flags().BoolVar(&options.WindowsLineEndings, "windows-line-endings", runtime.GOOS == "windows",
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||
cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, "Output format. One of: yaml|json.")
|
||||
cmd.Flags().BoolVar(&o.WindowsLineEndings, "windows-line-endings", o.WindowsLineEndings,
|
||||
"Defaults to the line ending native to your platform.")
|
||||
cmdutil.AddRecordVarFlag(cmd, &options.Record)
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
|
||||
return cmd
|
||||
|
174
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_set_last_applied.go
generated
vendored
174
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_set_last_applied.go
generated
vendored
@ -18,44 +18,44 @@ package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
apijson "k8s.io/apimachinery/pkg/util/json"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
type SetLastAppliedOptions struct {
|
||||
FilenameOptions resource.FilenameOptions
|
||||
Selector string
|
||||
InfoList []*resource.Info
|
||||
Mapper meta.RESTMapper
|
||||
Typer runtime.ObjectTyper
|
||||
Namespace string
|
||||
EnforceNamespace bool
|
||||
DryRun bool
|
||||
ShortOutput bool
|
||||
CreateAnnotation bool
|
||||
Output string
|
||||
PatchBufferList []PatchBuffer
|
||||
Factory cmdutil.Factory
|
||||
Out io.Writer
|
||||
ErrOut io.Writer
|
||||
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
FilenameOptions resource.FilenameOptions
|
||||
|
||||
infoList []*resource.Info
|
||||
namespace string
|
||||
enforceNamespace bool
|
||||
dryRun bool
|
||||
shortOutput bool
|
||||
output string
|
||||
patchBufferList []PatchBuffer
|
||||
builder *resource.Builder
|
||||
unstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
type PatchBuffer struct {
|
||||
@ -81,8 +81,15 @@ var (
|
||||
`))
|
||||
)
|
||||
|
||||
func NewCmdApplySetLastApplied(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
|
||||
options := &SetLastAppliedOptions{Out: out, ErrOut: err}
|
||||
func NewSetLastAppliedOptions(ioStreams genericclioptions.IOStreams) *SetLastAppliedOptions {
|
||||
return &SetLastAppliedOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("configured").WithTypeSetter(scheme.Scheme),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdApplySetLastApplied(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewSetLastAppliedOptions(ioStreams)
|
||||
cmd := &cobra.Command{
|
||||
Use: "set-last-applied -f FILENAME",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -90,42 +97,55 @@ func NewCmdApplySetLastApplied(f cmdutil.Factory, out, err io.Writer) *cobra.Com
|
||||
Long: applySetLastAppliedLong,
|
||||
Example: applySetLastAppliedExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.Complete(f, cmd))
|
||||
cmdutil.CheckErr(options.Validate(f, cmd))
|
||||
cmdutil.CheckErr(options.RunSetLastApplied(f, cmd))
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.RunSetLastApplied())
|
||||
},
|
||||
}
|
||||
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmd.Flags().BoolVar(&options.CreateAnnotation, "create-annotation", false, "Will create 'last-applied-configuration' annotations if current objects doesn't have one")
|
||||
usage := "that contains the last-applied-configuration annotations"
|
||||
kubectl.AddJsonFilenameFlag(cmd, &options.FilenameOptions.Filenames, "Filename, directory, or URL to files "+usage)
|
||||
cmd.Flags().BoolVar(&o.CreateAnnotation, "create-annotation", o.CreateAnnotation, "Will create 'last-applied-configuration' annotations if current objects doesn't have one")
|
||||
cmdutil.AddJsonFilenameFlag(cmd.Flags(), &o.FilenameOptions.Filenames, "Filename, directory, or URL to files that contains the last-applied-configuration annotations")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *SetLastAppliedOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
o.Output = cmdutil.GetFlagString(cmd, "output")
|
||||
o.ShortOutput = o.Output == "name"
|
||||
o.dryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
o.output = cmdutil.GetFlagString(cmd, "output")
|
||||
o.shortOutput = o.output == "name"
|
||||
|
||||
var err error
|
||||
o.Mapper, o.Typer = f.Object()
|
||||
o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.builder = f.NewBuilder()
|
||||
o.unstructuredClientForMapping = f.UnstructuredClientForMapping
|
||||
|
||||
o.Namespace, o.EnforceNamespace, err = f.DefaultNamespace()
|
||||
return err
|
||||
if o.dryRun {
|
||||
// TODO(juanvallejo): This can be cleaned up even further by creating
|
||||
// a PrintFlags struct that binds the --dry-run flag, and whose
|
||||
// ToPrinter method returns a printer that understands how to print
|
||||
// this success message.
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.PrintObj = printer.PrintObj
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
r := f.NewBuilder().
|
||||
func (o *SetLastAppliedOptions) Validate() error {
|
||||
r := o.builder.
|
||||
Unstructured().
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
FilenameParam(o.EnforceNamespace, &o.FilenameOptions).
|
||||
NamespaceParam(o.namespace).DefaultNamespace().
|
||||
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
|
||||
Flatten().
|
||||
Do()
|
||||
|
||||
@ -133,7 +153,7 @@ func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
patchBuf, diffBuf, patchType, err := editor.GetApplyPatch(info.Object, scheme.DefaultJSONEncoder())
|
||||
patchBuf, diffBuf, patchType, err := editor.GetApplyPatch(info.Object.(runtime.Unstructured))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -143,22 +163,22 @@ func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command)
|
||||
if errors.IsNotFound(err) {
|
||||
return err
|
||||
} else {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%v\nfrom server for:", info), info.Source, err)
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%s\nfrom server for:", info.String()), info.Source, err)
|
||||
}
|
||||
}
|
||||
originalBuf, err := kubectl.GetOriginalConfiguration(info.Mapping, info.Object)
|
||||
originalBuf, err := kubectl.GetOriginalConfiguration(info.Object)
|
||||
if err != nil {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%v\nfrom server for:", info), info.Source, err)
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%s\nfrom server for:", info.String()), info.Source, err)
|
||||
}
|
||||
if originalBuf == nil && !o.CreateAnnotation {
|
||||
return cmdutil.UsageErrorf(cmd, "no last-applied-configuration annotation found on resource: %s, to create the annotation, run the command with --create-annotation", info.Name)
|
||||
return fmt.Errorf("no last-applied-configuration annotation found on resource: %s, to create the annotation, run the command with --create-annotation", info.Name)
|
||||
}
|
||||
|
||||
//only add to PatchBufferList when changed
|
||||
if !bytes.Equal(cmdutil.StripComments(originalBuf), cmdutil.StripComments(diffBuf)) {
|
||||
p := PatchBuffer{Patch: patchBuf, PatchType: patchType}
|
||||
o.PatchBufferList = append(o.PatchBufferList, p)
|
||||
o.InfoList = append(o.InfoList, info)
|
||||
o.patchBufferList = append(o.patchBufferList, p)
|
||||
o.infoList = append(o.infoList, info)
|
||||
} else {
|
||||
fmt.Fprintf(o.Out, "set-last-applied %s: no changes required.\n", info.Name)
|
||||
}
|
||||
@ -168,68 +188,26 @@ func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command)
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *SetLastAppliedOptions) RunSetLastApplied(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
for i, patch := range o.PatchBufferList {
|
||||
info := o.InfoList[i]
|
||||
if !o.DryRun {
|
||||
func (o *SetLastAppliedOptions) RunSetLastApplied() error {
|
||||
for i, patch := range o.patchBufferList {
|
||||
info := o.infoList[i]
|
||||
finalObj := info.Object
|
||||
|
||||
if !o.dryRun {
|
||||
mapping := info.ResourceMapping()
|
||||
client, err := f.UnstructuredClientForMapping(mapping)
|
||||
client, err := o.unstructuredClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
helper := resource.NewHelper(client, mapping)
|
||||
patchedObj, err := helper.Patch(o.Namespace, info.Name, patch.PatchType, patch.Patch)
|
||||
finalObj, err = helper.Patch(o.namespace, info.Name, patch.PatchType, patch.Patch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(o.Output) > 0 && !o.ShortOutput {
|
||||
info.Refresh(patchedObj, false)
|
||||
return cmdutil.PrintObject(cmd, info.Object, o.Out)
|
||||
}
|
||||
cmdutil.PrintSuccess(o.ShortOutput, o.Out, info.Object, o.DryRun, "configured")
|
||||
|
||||
} else {
|
||||
err := o.formatPrinter(o.Output, patch.Patch, o.Out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmdutil.PrintSuccess(o.ShortOutput, o.Out, info.Object, o.DryRun, "configured")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *SetLastAppliedOptions) formatPrinter(output string, buf []byte, w io.Writer) error {
|
||||
yamlOutput, err := yaml.JSONToYAML(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch output {
|
||||
case "json":
|
||||
jsonBuffer := &bytes.Buffer{}
|
||||
err = json.Indent(jsonBuffer, buf, "", " ")
|
||||
if err != nil {
|
||||
if err := o.PrintObj(finalObj, o.Out); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(w, "%s\n", jsonBuffer.String())
|
||||
case "yaml":
|
||||
fmt.Fprintf(w, "%s\n", string(yamlOutput))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *SetLastAppliedOptions) getPatch(info *resource.Info) ([]byte, []byte, error) {
|
||||
objMap := map[string]map[string]map[string]string{}
|
||||
metadataMap := map[string]map[string]string{}
|
||||
annotationsMap := map[string]string{}
|
||||
localFile, err := runtime.Encode(scheme.DefaultJSONEncoder(), info.Object)
|
||||
if err != nil {
|
||||
return nil, localFile, err
|
||||
}
|
||||
annotationsMap[api.LastAppliedConfigAnnotation] = string(localFile)
|
||||
metadataMap["annotations"] = annotationsMap
|
||||
objMap["metadata"] = metadataMap
|
||||
jsonString, err := apijson.Marshal(objMap)
|
||||
return jsonString, localFile, err
|
||||
}
|
||||
|
1099
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_test.go
generated
vendored
1099
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_test.go
generated
vendored
File diff suppressed because it is too large
Load Diff
60
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_view_last_applied.go
generated
vendored
60
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_view_last_applied.go
generated
vendored
@ -20,14 +20,14 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -38,8 +38,8 @@ type ViewLastAppliedOptions struct {
|
||||
OutputFormat string
|
||||
All bool
|
||||
Factory cmdutil.Factory
|
||||
Out io.Writer
|
||||
ErrOut io.Writer
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
@ -57,8 +57,17 @@ var (
|
||||
kubectl apply view-last-applied -f deploy.yaml -o json`))
|
||||
)
|
||||
|
||||
func NewCmdApplyViewLastApplied(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
|
||||
options := &ViewLastAppliedOptions{Out: out, ErrOut: err}
|
||||
func NewViewLastAppliedOptions(ioStreams genericclioptions.IOStreams) *ViewLastAppliedOptions {
|
||||
return &ViewLastAppliedOptions{
|
||||
OutputFormat: "yaml",
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdApplyViewLastApplied(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := NewViewLastAppliedOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "view-last-applied (TYPE [NAME | -l label] | TYPE/NAME | -f FILENAME)",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -66,24 +75,23 @@ func NewCmdApplyViewLastApplied(f cmdutil.Factory, out, err io.Writer) *cobra.Co
|
||||
Long: applyViewLastAppliedLong,
|
||||
Example: applyViewLastAppliedExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.ValidateOutputArgs(cmd))
|
||||
cmdutil.CheckErr(options.Complete(f, args))
|
||||
cmdutil.CheckErr(options.Complete(cmd, f, args))
|
||||
cmdutil.CheckErr(options.Validate(cmd))
|
||||
cmdutil.CheckErr(options.RunApplyViewLastApplied())
|
||||
cmdutil.CheckErr(options.RunApplyViewLastApplied(cmd))
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringP("output", "o", "", "Output format. Must be one of yaml|json")
|
||||
cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().BoolVar(&options.All, "all", false, "Select all resources in the namespace of the specified resource types")
|
||||
cmd.Flags().StringVarP(&options.OutputFormat, "output", "o", options.OutputFormat, "Output format. Must be one of yaml|json")
|
||||
cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().BoolVar(&options.All, "all", options.All, "Select all resources in the namespace of the specified resource types")
|
||||
usage := "that contains the last-applied-configuration annotations"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *ViewLastAppliedOptions) Complete(f cmdutil.Factory, args []string) error {
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
func (o *ViewLastAppliedOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args []string) error {
|
||||
cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -108,7 +116,7 @@ func (o *ViewLastAppliedOptions) Complete(f cmdutil.Factory, args []string) erro
|
||||
return err
|
||||
}
|
||||
|
||||
configString, err := kubectl.GetOriginalConfiguration(info.Mapping, info.Object)
|
||||
configString, err := kubectl.GetOriginalConfiguration(info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -130,7 +138,7 @@ func (o *ViewLastAppliedOptions) Validate(cmd *cobra.Command) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ViewLastAppliedOptions) RunApplyViewLastApplied() error {
|
||||
func (o *ViewLastAppliedOptions) RunApplyViewLastApplied(cmd *cobra.Command) error {
|
||||
for _, str := range o.LastAppliedConfigurationList {
|
||||
switch o.OutputFormat {
|
||||
case "json":
|
||||
@ -146,23 +154,13 @@ func (o *ViewLastAppliedOptions) RunApplyViewLastApplied() error {
|
||||
return err
|
||||
}
|
||||
fmt.Fprint(o.Out, string(yamlOutput))
|
||||
default:
|
||||
return cmdutil.UsageErrorf(
|
||||
cmd,
|
||||
"Unexpected -o output mode: %s, the flag 'output' must be one of yaml|json",
|
||||
o.OutputFormat)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ViewLastAppliedOptions) ValidateOutputArgs(cmd *cobra.Command) error {
|
||||
format := cmdutil.GetFlagString(cmd, "output")
|
||||
switch format {
|
||||
case "json":
|
||||
o.OutputFormat = "json"
|
||||
return nil
|
||||
// If flag -o is not specified, use yaml as default
|
||||
case "yaml", "":
|
||||
o.OutputFormat = "yaml"
|
||||
return nil
|
||||
default:
|
||||
return cmdutil.UsageErrorf(cmd, "Unexpected -o output mode: %s, the flag 'output' must be one of yaml|json", format)
|
||||
}
|
||||
}
|
||||
|
49
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/attach.go
generated
vendored
49
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/attach.go
generated
vendored
@ -35,6 +35,8 @@ import (
|
||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -60,12 +62,10 @@ const (
|
||||
defaultPodLogsTimeout = 20 * time.Second
|
||||
)
|
||||
|
||||
func NewCmdAttach(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command {
|
||||
options := &AttachOptions{
|
||||
func NewCmdAttach(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := &AttachOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
In: cmdIn,
|
||||
Out: cmdOut,
|
||||
Err: cmdErr,
|
||||
IOStreams: streams,
|
||||
},
|
||||
|
||||
Attach: &DefaultRemoteAttach{},
|
||||
@ -77,15 +77,15 @@ func NewCmdAttach(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer)
|
||||
Long: "Attach to a process that is already running inside an existing container.",
|
||||
Example: attachExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Validate())
|
||||
cmdutil.CheckErr(options.Run())
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
}
|
||||
cmdutil.AddPodRunningTimeoutFlag(cmd, defaultPodAttachTimeout)
|
||||
cmd.Flags().StringVarP(&options.ContainerName, "container", "c", "", "Container name. If omitted, the first container in the pod will be chosen")
|
||||
cmd.Flags().BoolVarP(&options.Stdin, "stdin", "i", false, "Pass stdin to the container")
|
||||
cmd.Flags().BoolVarP(&options.TTY, "tty", "t", false, "Stdin is a TTY")
|
||||
cmd.Flags().StringVarP(&o.ContainerName, "container", "c", o.ContainerName, "Container name. If omitted, the first container in the pod will be chosen")
|
||||
cmd.Flags().BoolVarP(&o.Stdin, "stdin", "i", o.Stdin, "Pass stdin to the container")
|
||||
cmd.Flags().BoolVarP(&o.TTY, "tty", "t", o.TTY, "Stdin is a TTY")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -135,7 +135,7 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [
|
||||
return cmdutil.UsageErrorf(cmd, "expected POD, TYPE/NAME, or TYPE NAME, (at most 2 arguments) saw %d: %v", len(argsIn), argsIn)
|
||||
}
|
||||
|
||||
namespace, _, err := f.DefaultNamespace()
|
||||
namespace, _, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -146,7 +146,7 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [
|
||||
}
|
||||
|
||||
builder := f.NewBuilder().
|
||||
Internal().
|
||||
WithScheme(legacyscheme.Scheme).
|
||||
NamespaceParam(namespace).DefaultNamespace()
|
||||
|
||||
switch len(argsIn) {
|
||||
@ -161,7 +161,7 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [
|
||||
return err
|
||||
}
|
||||
|
||||
attachablePod, err := f.AttachablePodForObject(obj, p.GetPodTimeout)
|
||||
attachablePod, err := polymorphichelpers.AttachablePodForObjectFn(f, obj, p.GetPodTimeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -178,7 +178,7 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [
|
||||
p.SuggestedCmdUsage = fmt.Sprintf("Use '%s describe pod/%s -n %s' to see all of the containers in this pod.", fullCmdName, p.PodName, p.Namespace)
|
||||
}
|
||||
|
||||
config, err := f.ClientConfig()
|
||||
config, err := f.ToRESTConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -188,6 +188,7 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.PodClient = clientset.Core()
|
||||
|
||||
if p.CommandName == "" {
|
||||
@ -203,7 +204,7 @@ func (p *AttachOptions) Validate() error {
|
||||
if len(p.PodName) == 0 {
|
||||
allErrs = append(allErrs, errors.New("pod name must be specified"))
|
||||
}
|
||||
if p.Out == nil || p.Err == nil {
|
||||
if p.Out == nil || p.ErrOut == nil {
|
||||
allErrs = append(allErrs, errors.New("both output and error output must be provided"))
|
||||
}
|
||||
if p.Attach == nil || p.PodClient == nil || p.Config == nil {
|
||||
@ -236,8 +237,8 @@ func (p *AttachOptions) Run() error {
|
||||
}
|
||||
if p.TTY && !containerToAttach.TTY {
|
||||
p.TTY = false
|
||||
if p.Err != nil {
|
||||
fmt.Fprintf(p.Err, "Unable to use a TTY - container %s did not allocate one\n", containerToAttach.Name)
|
||||
if p.ErrOut != nil {
|
||||
fmt.Fprintf(p.ErrOut, "Unable to use a TTY - container %s did not allocate one\n", containerToAttach.Name)
|
||||
}
|
||||
} else if !p.TTY && containerToAttach.TTY {
|
||||
// the container was launched with a TTY, so we have to force a TTY here, otherwise you'll get
|
||||
@ -249,7 +250,7 @@ func (p *AttachOptions) Run() error {
|
||||
t := p.setupTTY()
|
||||
|
||||
// save p.Err so we can print the command prompt message below
|
||||
stderr := p.Err
|
||||
stderr := p.ErrOut
|
||||
|
||||
var sizeQueue remotecommand.TerminalSizeQueue
|
||||
if t.Raw {
|
||||
@ -266,7 +267,7 @@ func (p *AttachOptions) Run() error {
|
||||
|
||||
// unset p.Err if it was previously set because both stdout and stderr go over p.Out when tty is
|
||||
// true
|
||||
p.Err = nil
|
||||
p.ErrOut = nil
|
||||
}
|
||||
|
||||
fn := func() error {
|
||||
@ -284,11 +285,11 @@ func (p *AttachOptions) Run() error {
|
||||
Container: containerToAttach.Name,
|
||||
Stdin: p.Stdin,
|
||||
Stdout: p.Out != nil,
|
||||
Stderr: p.Err != nil,
|
||||
Stderr: p.ErrOut != nil,
|
||||
TTY: t.Raw,
|
||||
}, legacyscheme.ParameterCodec)
|
||||
|
||||
return p.Attach.Attach("POST", req.URL(), p.Config, p.In, p.Out, p.Err, t.Raw, sizeQueue)
|
||||
return p.Attach.Attach("POST", req.URL(), p.Config, p.In, p.Out, p.ErrOut, t.Raw, sizeQueue)
|
||||
}
|
||||
|
||||
if !p.Quiet && stderr != nil {
|
||||
@ -322,8 +323,8 @@ func (p *AttachOptions) containerToAttachTo(pod *api.Pod) (*api.Container, error
|
||||
}
|
||||
|
||||
if len(p.SuggestedCmdUsage) > 0 {
|
||||
fmt.Fprintf(p.Err, "Defaulting container name to %s.\n", pod.Spec.Containers[0].Name)
|
||||
fmt.Fprintf(p.Err, "%s\n", p.SuggestedCmdUsage)
|
||||
fmt.Fprintf(p.ErrOut, "Defaulting container name to %s.\n", pod.Spec.Containers[0].Name)
|
||||
fmt.Fprintf(p.ErrOut, "%s\n", p.SuggestedCmdUsage)
|
||||
}
|
||||
|
||||
glog.V(4).Infof("defaulting container name to %s", pod.Spec.Containers[0].Name)
|
||||
|
311
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/attach_test.go
generated
vendored
311
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/attach_test.go
generated
vendored
@ -17,7 +17,6 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@ -38,6 +37,7 @@ import (
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
@ -139,48 +139,51 @@ func TestPodAndContainerAttach(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
ns := legacyscheme.Codecs
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
if test.obj != nil {
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, test.obj)}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
cmd := &cobra.Command{}
|
||||
options := test.p
|
||||
cmdutil.AddPodRunningTimeoutFlag(cmd, test.timeout)
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
if test.obj != nil {
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, test.obj)}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
err := options.Complete(tf, cmd, test.args)
|
||||
if test.expectError && err == nil {
|
||||
t.Errorf("%s: unexpected non-error", test.name)
|
||||
}
|
||||
if !test.expectError && err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", test.name, err)
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if options.PodName != test.expectedPod {
|
||||
t.Errorf("%s: expected: %s, got: %s", test.name, test.expectedPod, options.PodName)
|
||||
}
|
||||
if options.ContainerName != test.expectedContainer {
|
||||
t.Errorf("%s: expected: %s, got: %s", test.name, test.expectedContainer, options.ContainerName)
|
||||
}
|
||||
cmd := &cobra.Command{}
|
||||
options := test.p
|
||||
cmdutil.AddPodRunningTimeoutFlag(cmd, test.timeout)
|
||||
|
||||
err := options.Complete(tf, cmd, test.args)
|
||||
if test.expectError && err == nil {
|
||||
t.Errorf("%s: unexpected non-error", test.name)
|
||||
}
|
||||
if !test.expectError && err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", test.name, err)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if options.PodName != test.expectedPod {
|
||||
t.Errorf("%s: expected: %s, got: %s", test.name, test.expectedPod, options.PodName)
|
||||
}
|
||||
if options.ContainerName != test.expectedContainer {
|
||||
t.Errorf("%s: expected: %s, got: %s", test.name, test.expectedContainer, options.ContainerName)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttach(t *testing.T) {
|
||||
version := legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion.Version
|
||||
version := "v1"
|
||||
tests := []struct {
|
||||
name, version, podPath, fetchPodPath, attachPath, container string
|
||||
pod *api.Pod
|
||||
@ -219,79 +222,76 @@ func TestAttach(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
ns := legacyscheme.Codecs
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == test.podPath && m == "GET":
|
||||
body := objBody(codec, test.pod)
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
case p == test.fetchPodPath && m == "GET":
|
||||
body := objBody(codec, test.pod)
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
default:
|
||||
// Ensures no GET is performed when deleting by name
|
||||
t.Errorf("%s: unexpected request: %s %#v\n%#v", p, req.Method, req.URL, req)
|
||||
return nil, fmt.Errorf("unexpected request")
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs, GroupVersion: &schema.GroupVersion{Version: test.version}}}
|
||||
bufOut := bytes.NewBuffer([]byte{})
|
||||
bufErr := bytes.NewBuffer([]byte{})
|
||||
bufIn := bytes.NewBuffer([]byte{})
|
||||
remoteAttach := &fakeRemoteAttach{}
|
||||
if test.remoteAttachErr {
|
||||
remoteAttach.err = fmt.Errorf("attach error")
|
||||
}
|
||||
params := &AttachOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
ContainerName: test.container,
|
||||
In: bufIn,
|
||||
Out: bufOut,
|
||||
Err: bufErr,
|
||||
},
|
||||
Attach: remoteAttach,
|
||||
GetPodTimeout: 1000,
|
||||
}
|
||||
cmd := &cobra.Command{}
|
||||
cmdutil.AddPodRunningTimeoutFlag(cmd, 1000)
|
||||
if err := params.Complete(tf, cmd, []string{"foo"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err := params.Run()
|
||||
if test.exepctedErr != "" && err.Error() != test.exepctedErr {
|
||||
t.Errorf("%s: Unexpected exec error: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
if test.exepctedErr == "" && err != nil {
|
||||
t.Errorf("%s: Unexpected error: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
if test.exepctedErr != "" {
|
||||
continue
|
||||
}
|
||||
if remoteAttach.url.Path != test.attachPath {
|
||||
t.Errorf("%s: Did not get expected path for exec request: %q %q", test.name, test.attachPath, remoteAttach.url.Path)
|
||||
continue
|
||||
}
|
||||
if remoteAttach.method != "POST" {
|
||||
t.Errorf("%s: Did not get method for attach request: %s", test.name, remoteAttach.method)
|
||||
}
|
||||
if remoteAttach.url.Query().Get("container") != "bar" {
|
||||
t.Errorf("%s: Did not have query parameters: %s", test.name, remoteAttach.url.Query())
|
||||
}
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == test.podPath && m == "GET":
|
||||
body := objBody(codec, test.pod)
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
case p == test.fetchPodPath && m == "GET":
|
||||
body := objBody(codec, test.pod)
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
default:
|
||||
t.Errorf("%s: unexpected request: %s %#v\n%#v", p, req.Method, req.URL, req)
|
||||
return nil, fmt.Errorf("unexpected request")
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs, GroupVersion: &schema.GroupVersion{Version: test.version}}}
|
||||
remoteAttach := &fakeRemoteAttach{}
|
||||
if test.remoteAttachErr {
|
||||
remoteAttach.err = fmt.Errorf("attach error")
|
||||
}
|
||||
params := &AttachOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
ContainerName: test.container,
|
||||
IOStreams: genericclioptions.NewTestIOStreamsDiscard(),
|
||||
},
|
||||
Attach: remoteAttach,
|
||||
GetPodTimeout: 1000,
|
||||
}
|
||||
cmd := &cobra.Command{}
|
||||
cmdutil.AddPodRunningTimeoutFlag(cmd, 1000)
|
||||
if err := params.Complete(tf, cmd, []string{"foo"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err := params.Run()
|
||||
if test.exepctedErr != "" && err.Error() != test.exepctedErr {
|
||||
t.Errorf("%s: Unexpected exec error: %v", test.name, err)
|
||||
return
|
||||
}
|
||||
if test.exepctedErr == "" && err != nil {
|
||||
t.Errorf("%s: Unexpected error: %v", test.name, err)
|
||||
return
|
||||
}
|
||||
if test.exepctedErr != "" {
|
||||
return
|
||||
}
|
||||
if remoteAttach.url.Path != test.attachPath {
|
||||
t.Errorf("%s: Did not get expected path for exec request: %q %q", test.name, test.attachPath, remoteAttach.url.Path)
|
||||
return
|
||||
}
|
||||
if remoteAttach.method != "POST" {
|
||||
t.Errorf("%s: Did not get method for attach request: %s", test.name, remoteAttach.method)
|
||||
}
|
||||
if remoteAttach.url.Query().Get("container") != "bar" {
|
||||
t.Errorf("%s: Did not have query parameters: %s", test.name, remoteAttach.url.Query())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttachWarnings(t *testing.T) {
|
||||
version := legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion.Version
|
||||
version := "v1"
|
||||
tests := []struct {
|
||||
name, container, version, podPath, fetchPodPath, expectedErr string
|
||||
pod *api.Pod
|
||||
@ -309,62 +309,61 @@ func TestAttachWarnings(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
ns := legacyscheme.Codecs
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == test.podPath && m == "GET":
|
||||
body := objBody(codec, test.pod)
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
case p == test.fetchPodPath && m == "GET":
|
||||
body := objBody(codec, test.pod)
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
default:
|
||||
t.Errorf("%s: unexpected request: %s %#v\n%#v", test.name, req.Method, req.URL, req)
|
||||
return nil, fmt.Errorf("unexpected request")
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs, GroupVersion: &schema.GroupVersion{Version: test.version}}}
|
||||
bufOut := bytes.NewBuffer([]byte{})
|
||||
bufErr := bytes.NewBuffer([]byte{})
|
||||
bufIn := bytes.NewBuffer([]byte{})
|
||||
ex := &fakeRemoteAttach{}
|
||||
params := &AttachOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
ContainerName: test.container,
|
||||
In: bufIn,
|
||||
Out: bufOut,
|
||||
Err: bufErr,
|
||||
Stdin: test.stdin,
|
||||
TTY: test.tty,
|
||||
},
|
||||
Attach: ex,
|
||||
GetPodTimeout: 1000,
|
||||
}
|
||||
cmd := &cobra.Command{}
|
||||
cmdutil.AddPodRunningTimeoutFlag(cmd, 1000)
|
||||
if err := params.Complete(tf, cmd, []string{"foo"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := params.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
if test.stdin && test.tty {
|
||||
if !test.pod.Spec.Containers[0].TTY {
|
||||
if !strings.Contains(bufErr.String(), test.expectedErr) {
|
||||
t.Errorf("%s: Expected TTY fallback warning for attach request: %s", test.name, bufErr.String())
|
||||
continue
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == test.podPath && m == "GET":
|
||||
body := objBody(codec, test.pod)
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
case p == test.fetchPodPath && m == "GET":
|
||||
body := objBody(codec, test.pod)
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
default:
|
||||
t.Errorf("%s: unexpected request: %s %#v\n%#v", test.name, req.Method, req.URL, req)
|
||||
return nil, fmt.Errorf("unexpected request")
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs, GroupVersion: &schema.GroupVersion{Version: test.version}}}
|
||||
streams, _, _, bufErr := genericclioptions.NewTestIOStreams()
|
||||
ex := &fakeRemoteAttach{}
|
||||
params := &AttachOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
ContainerName: test.container,
|
||||
IOStreams: streams,
|
||||
Stdin: test.stdin,
|
||||
TTY: test.tty,
|
||||
},
|
||||
Attach: ex,
|
||||
GetPodTimeout: 1000,
|
||||
}
|
||||
cmd := &cobra.Command{}
|
||||
cmdutil.AddPodRunningTimeoutFlag(cmd, 1000)
|
||||
if err := params.Complete(tf, cmd, []string{"foo"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := params.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if test.stdin && test.tty {
|
||||
if !test.pod.Spec.Containers[0].TTY {
|
||||
if !strings.Contains(bufErr.String(), test.expectedErr) {
|
||||
t.Errorf("%s: Expected TTY fallback warning for attach request: %s", test.name, bufErr.String())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
11
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/BUILD
generated
vendored
11
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/BUILD
generated
vendored
@ -17,18 +17,21 @@ go_library(
|
||||
],
|
||||
deps = [
|
||||
"//pkg/apis/authorization:go_default_library",
|
||||
"//pkg/apis/rbac:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/authorization/internalversion:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion:go_default_library",
|
||||
"//pkg/kubectl/cmd/templates:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/printers:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/resource:go_default_library",
|
||||
"//pkg/kubectl/scheme:go_default_library",
|
||||
"//pkg/registry/rbac/reconciliation:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/rbac/v1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
11
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/auth.go
generated
vendored
11
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/auth.go
generated
vendored
@ -17,24 +17,23 @@ limitations under the License.
|
||||
package auth
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
)
|
||||
|
||||
func NewCmdAuth(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
func NewCmdAuth(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
// Parent command to which all subcommands are added.
|
||||
cmds := &cobra.Command{
|
||||
Use: "auth",
|
||||
Short: "Inspect authorization",
|
||||
Long: `Inspect authorization`,
|
||||
Run: cmdutil.DefaultSubCommandRun(errOut),
|
||||
Run: cmdutil.DefaultSubCommandRun(streams.ErrOut),
|
||||
}
|
||||
|
||||
cmds.AddCommand(NewCmdCanI(f, out, errOut))
|
||||
cmds.AddCommand(NewCmdReconcile(f, out, errOut))
|
||||
cmds.AddCommand(NewCmdCanI(f, streams))
|
||||
cmds.AddCommand(NewCmdReconcile(f, streams))
|
||||
|
||||
return cmds
|
||||
}
|
||||
|
25
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/cani.go
generated
vendored
25
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/cani.go
generated
vendored
@ -19,12 +19,12 @@ package auth
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
@ -48,8 +48,7 @@ type CanIOptions struct {
|
||||
Subresource string
|
||||
ResourceName string
|
||||
|
||||
Out io.Writer
|
||||
Err io.Writer
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
@ -81,10 +80,9 @@ var (
|
||||
kubectl auth can-i get /logs/`)
|
||||
)
|
||||
|
||||
func NewCmdCanI(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
|
||||
func NewCmdCanI(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := &CanIOptions{
|
||||
Out: out,
|
||||
Err: err,
|
||||
IOStreams: streams,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
@ -99,7 +97,7 @@ func NewCmdCanI(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
|
||||
|
||||
allowed, err := o.RunAccessCheck()
|
||||
if err == nil {
|
||||
if o.Quiet && !allowed {
|
||||
if !allowed {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@ -110,7 +108,7 @@ func NewCmdCanI(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
|
||||
|
||||
cmd.Flags().BoolVar(&o.AllNamespaces, "all-namespaces", o.AllNamespaces, "If true, check the specified action in all namespaces.")
|
||||
cmd.Flags().BoolVarP(&o.Quiet, "quiet", "q", o.Quiet, "If true, suppress output and just return the exit code.")
|
||||
cmd.Flags().StringVar(&o.Subresource, "subresource", "", "SubResource such as pod/log or deployment/scale")
|
||||
cmd.Flags().StringVar(&o.Subresource, "subresource", o.Subresource, "SubResource such as pod/log or deployment/scale")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -127,7 +125,10 @@ func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error {
|
||||
break
|
||||
}
|
||||
resourceTokens := strings.SplitN(args[1], "/", 2)
|
||||
restMapper, _ := f.Object()
|
||||
restMapper, err := f.ToRESTMapper()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.Resource = o.resourceFor(restMapper, resourceTokens[0])
|
||||
if len(resourceTokens) > 1 {
|
||||
o.ResourceName = resourceTokens[1]
|
||||
@ -145,7 +146,7 @@ func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error {
|
||||
|
||||
o.Namespace = ""
|
||||
if !o.AllNamespaces {
|
||||
o.Namespace, _, err = f.DefaultNamespace()
|
||||
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -229,9 +230,9 @@ func (o *CanIOptions) resourceFor(mapper meta.RESTMapper, resourceArg string) sc
|
||||
gvr, err = mapper.ResourceFor(groupResource.WithVersion(""))
|
||||
if err != nil {
|
||||
if len(groupResource.Group) == 0 {
|
||||
fmt.Fprintf(o.Err, "Warning: the server doesn't have a resource type '%s'\n", groupResource.Resource)
|
||||
fmt.Fprintf(o.ErrOut, "Warning: the server doesn't have a resource type '%s'\n", groupResource.Resource)
|
||||
} else {
|
||||
fmt.Fprintf(o.Err, "Warning: the server doesn't have a resource type '%s' in group '%s'\n", groupResource.Resource, groupResource.Group)
|
||||
fmt.Fprintf(o.ErrOut, "Warning: the server doesn't have a resource type '%s' in group '%s'\n", groupResource.Resource, groupResource.Group)
|
||||
}
|
||||
return schema.GroupVersionResource{Resource: resourceArg}
|
||||
}
|
||||
|
107
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/cani_test.go
generated
vendored
107
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/cani_test.go
generated
vendored
@ -117,64 +117,67 @@ func TestRunAccessCheck(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test.o.Out = ioutil.Discard
|
||||
test.o.Err = ioutil.Discard
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
test.o.Out = ioutil.Discard
|
||||
test.o.ErrOut = ioutil.Discard
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
expectPath := "/apis/authorization.k8s.io/v1/selfsubjectaccessreviews"
|
||||
if req.URL.Path != expectPath {
|
||||
t.Errorf("%s: expected %v, got %v", test.name, expectPath, req.URL.Path)
|
||||
return nil, nil
|
||||
}
|
||||
bodyBits, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
t.Errorf("%s: %v", test.name, err)
|
||||
return nil, nil
|
||||
}
|
||||
body := string(bodyBits)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
for _, expectedBody := range test.expectedBodyStrings {
|
||||
if !strings.Contains(body, expectedBody) {
|
||||
t.Errorf("%s expecting %s in %s", test.name, expectedBody, body)
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
expectPath := "/apis/authorization.k8s.io/v1/selfsubjectaccessreviews"
|
||||
if req.URL.Path != expectPath {
|
||||
t.Errorf("%s: expected %v, got %v", test.name, expectPath, req.URL.Path)
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
bodyBits, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
t.Errorf("%s: %v", test.name, err)
|
||||
return nil, nil
|
||||
}
|
||||
body := string(bodyBits)
|
||||
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: ioutil.NopCloser(bytes.NewBufferString(
|
||||
fmt.Sprintf(`{"kind":"SelfSubjectAccessReview","apiVersion":"authorization.k8s.io/v1","status":{"allowed":%v}}`, test.allowed),
|
||||
)),
|
||||
},
|
||||
test.serverErr
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}}
|
||||
for _, expectedBody := range test.expectedBodyStrings {
|
||||
if !strings.Contains(body, expectedBody) {
|
||||
t.Errorf("%s expecting %s in %s", test.name, expectedBody, body)
|
||||
}
|
||||
}
|
||||
|
||||
if err := test.o.Complete(tf, test.args); err != nil {
|
||||
t.Errorf("%s: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: ioutil.NopCloser(bytes.NewBufferString(
|
||||
fmt.Sprintf(`{"kind":"SelfSubjectAccessReview","apiVersion":"authorization.k8s.io/v1","status":{"allowed":%v}}`, test.allowed),
|
||||
)),
|
||||
},
|
||||
test.serverErr
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}}
|
||||
|
||||
actualAllowed, err := test.o.RunAccessCheck()
|
||||
switch {
|
||||
case test.serverErr == nil && err == nil:
|
||||
// pass
|
||||
case err != nil && test.serverErr != nil && strings.Contains(err.Error(), test.serverErr.Error()):
|
||||
// pass
|
||||
default:
|
||||
t.Errorf("%s: expected %v, got %v", test.name, test.serverErr, err)
|
||||
continue
|
||||
}
|
||||
if actualAllowed != test.allowed {
|
||||
t.Errorf("%s: expected %v, got %v", test.name, test.allowed, actualAllowed)
|
||||
continue
|
||||
}
|
||||
if err := test.o.Complete(tf, test.args); err != nil {
|
||||
t.Errorf("%s: %v", test.name, err)
|
||||
return
|
||||
}
|
||||
|
||||
actualAllowed, err := test.o.RunAccessCheck()
|
||||
switch {
|
||||
case test.serverErr == nil && err == nil:
|
||||
// pass
|
||||
case err != nil && test.serverErr != nil && strings.Contains(err.Error(), test.serverErr.Error()):
|
||||
// pass
|
||||
default:
|
||||
t.Errorf("%s: expected %v, got %v", test.name, test.serverErr, err)
|
||||
return
|
||||
}
|
||||
if actualAllowed != test.allowed {
|
||||
t.Errorf("%s: expected %v, got %v", test.name, test.allowed, actualAllowed)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
126
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/reconcile.go
generated
vendored
126
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/auth/reconcile.go
generated
vendored
@ -18,31 +18,36 @@ package auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
internalcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||
internalrbacclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
rbacv1client "k8s.io/client-go/kubernetes/typed/rbac/v1"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/registry/rbac/reconciliation"
|
||||
)
|
||||
|
||||
// ReconcileOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
|
||||
// referencing the cmd.Flags()
|
||||
type ReconcileOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
FilenameOptions *resource.FilenameOptions
|
||||
DryRun bool
|
||||
|
||||
Visitor resource.Visitor
|
||||
RBACClient internalrbacclient.RbacInterface
|
||||
NamespaceClient internalcoreclient.NamespaceInterface
|
||||
RBACClient rbacv1client.RbacV1Interface
|
||||
NamespaceClient corev1client.CoreV1Interface
|
||||
|
||||
Print func(*resource.Info) error
|
||||
PrintObject printers.ResourcePrinterFunc
|
||||
|
||||
Out io.Writer
|
||||
Err io.Writer
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
@ -56,12 +61,16 @@ var (
|
||||
kubectl auth reconcile -f my-rbac-rules.yaml`)
|
||||
)
|
||||
|
||||
func NewCmdReconcile(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
|
||||
fileOptions := &resource.FilenameOptions{}
|
||||
o := &ReconcileOptions{
|
||||
Out: out,
|
||||
Err: err,
|
||||
func NewReconcileOptions(ioStreams genericclioptions.IOStreams) *ReconcileOptions {
|
||||
return &ReconcileOptions{
|
||||
FilenameOptions: &resource.FilenameOptions{},
|
||||
PrintFlags: genericclioptions.NewPrintFlags("reconciled").WithTypeSetter(scheme.Scheme),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdReconcile(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewReconcileOptions(streams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "reconcile -f FILENAME",
|
||||
@ -70,35 +79,36 @@ func NewCmdReconcile(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
|
||||
Long: reconcileLong,
|
||||
Example: reconcileExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(cmd, f, args, fileOptions))
|
||||
cmdutil.CheckErr(o.Complete(cmd, f, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.RunReconcile())
|
||||
},
|
||||
}
|
||||
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
usage := "identifying the resource to reconcile."
|
||||
cmdutil.AddFilenameOptionFlags(cmd, fileOptions, usage)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, "identifying the resource to reconcile.")
|
||||
cmd.Flags().BoolVar(&o.DryRun, "dry-run", o.DryRun, "If true, display results but do not submit changes")
|
||||
cmd.MarkFlagRequired("filename")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *ReconcileOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args []string, options *resource.FilenameOptions) error {
|
||||
func (o *ReconcileOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args []string) error {
|
||||
if len(args) > 0 {
|
||||
return errors.New("no arguments are allowed")
|
||||
}
|
||||
|
||||
namespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
namespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := f.NewBuilder().
|
||||
Internal().
|
||||
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options).
|
||||
FilenameParam(enforceNamespace, o.FilenameOptions).
|
||||
Flatten().
|
||||
Do()
|
||||
|
||||
@ -107,24 +117,28 @@ func (o *ReconcileOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args
|
||||
}
|
||||
o.Visitor = r
|
||||
|
||||
client, err := f.ClientSet()
|
||||
clientConfig, err := f.ToRESTConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.RBACClient = client.Rbac()
|
||||
o.NamespaceClient = client.Core().Namespaces()
|
||||
|
||||
dryRun := false
|
||||
output := cmdutil.GetFlagString(cmd, "output")
|
||||
shortOutput := output == "name"
|
||||
o.Print = func(info *resource.Info) error {
|
||||
if len(output) > 0 && !shortOutput {
|
||||
return cmdutil.PrintObject(cmd, info.Object, o.Out)
|
||||
}
|
||||
cmdutil.PrintSuccess(shortOutput, o.Out, info.Object, dryRun, "reconciled")
|
||||
return nil
|
||||
o.RBACClient, err = rbacv1client.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.NamespaceClient, err = corev1client.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.PrintObject = printer.PrintObj
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -138,13 +152,13 @@ func (o *ReconcileOptions) Validate() error {
|
||||
if o.NamespaceClient == nil {
|
||||
return errors.New("ReconcileOptions.NamespaceClient must be set")
|
||||
}
|
||||
if o.Print == nil {
|
||||
if o.PrintObject == nil {
|
||||
return errors.New("ReconcileOptions.Print must be set")
|
||||
}
|
||||
if o.Out == nil {
|
||||
return errors.New("ReconcileOptions.Out must be set")
|
||||
}
|
||||
if o.Err == nil {
|
||||
if o.ErrOut == nil {
|
||||
return errors.New("ReconcileOptions.Err must be set")
|
||||
}
|
||||
return nil
|
||||
@ -156,18 +170,14 @@ func (o *ReconcileOptions) RunReconcile() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// shallowInfoCopy this is used to later twiddle the Object for printing
|
||||
// we really need more straightforward printing options
|
||||
shallowInfoCopy := *info
|
||||
|
||||
switch t := info.Object.(type) {
|
||||
case *rbac.Role:
|
||||
case *rbacv1.Role:
|
||||
reconcileOptions := reconciliation.ReconcileRoleOptions{
|
||||
Confirm: true,
|
||||
Confirm: !o.DryRun,
|
||||
RemoveExtraPermissions: false,
|
||||
Role: reconciliation.RoleRuleOwner{Role: t},
|
||||
Client: reconciliation.RoleModifier{
|
||||
NamespaceClient: o.NamespaceClient,
|
||||
NamespaceClient: o.NamespaceClient.Namespaces(),
|
||||
Client: o.RBACClient,
|
||||
},
|
||||
}
|
||||
@ -175,12 +185,11 @@ func (o *ReconcileOptions) RunReconcile() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
shallowInfoCopy.Object = result.Role.GetObject()
|
||||
o.Print(&shallowInfoCopy)
|
||||
o.PrintObject(result.Role.GetObject(), o.Out)
|
||||
|
||||
case *rbac.ClusterRole:
|
||||
case *rbacv1.ClusterRole:
|
||||
reconcileOptions := reconciliation.ReconcileRoleOptions{
|
||||
Confirm: true,
|
||||
Confirm: !o.DryRun,
|
||||
RemoveExtraPermissions: false,
|
||||
Role: reconciliation.ClusterRoleRuleOwner{ClusterRole: t},
|
||||
Client: reconciliation.ClusterRoleModifier{
|
||||
@ -191,29 +200,27 @@ func (o *ReconcileOptions) RunReconcile() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
shallowInfoCopy.Object = result.Role.GetObject()
|
||||
o.Print(&shallowInfoCopy)
|
||||
o.PrintObject(result.Role.GetObject(), o.Out)
|
||||
|
||||
case *rbac.RoleBinding:
|
||||
case *rbacv1.RoleBinding:
|
||||
reconcileOptions := reconciliation.ReconcileRoleBindingOptions{
|
||||
Confirm: true,
|
||||
Confirm: !o.DryRun,
|
||||
RemoveExtraSubjects: false,
|
||||
RoleBinding: reconciliation.RoleBindingAdapter{RoleBinding: t},
|
||||
Client: reconciliation.RoleBindingClientAdapter{
|
||||
Client: o.RBACClient,
|
||||
NamespaceClient: o.NamespaceClient,
|
||||
NamespaceClient: o.NamespaceClient.Namespaces(),
|
||||
},
|
||||
}
|
||||
result, err := reconcileOptions.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
shallowInfoCopy.Object = result.RoleBinding.GetObject()
|
||||
o.Print(&shallowInfoCopy)
|
||||
o.PrintObject(result.RoleBinding.GetObject(), o.Out)
|
||||
|
||||
case *rbac.ClusterRoleBinding:
|
||||
case *rbacv1.ClusterRoleBinding:
|
||||
reconcileOptions := reconciliation.ReconcileRoleBindingOptions{
|
||||
Confirm: true,
|
||||
Confirm: !o.DryRun,
|
||||
RemoveExtraSubjects: false,
|
||||
RoleBinding: reconciliation.ClusterRoleBindingAdapter{ClusterRoleBinding: t},
|
||||
Client: reconciliation.ClusterRoleBindingClientAdapter{
|
||||
@ -224,8 +231,7 @@ func (o *ReconcileOptions) RunReconcile() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
shallowInfoCopy.Object = result.RoleBinding.GetObject()
|
||||
o.Print(&shallowInfoCopy)
|
||||
o.PrintObject(result.RoleBinding.GetObject(), o.Out)
|
||||
|
||||
default:
|
||||
glog.V(1).Infof("skipping %#v", info.Object.GetObjectKind())
|
||||
|
244
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/autoscale.go
generated
vendored
244
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/autoscale.go
generated
vendored
@ -18,16 +18,23 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
autoscalingv1 "k8s.io/api/autoscaling/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
autoscalingv1client "k8s.io/client-go/kubernetes/typed/autoscaling/v1"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -45,11 +52,50 @@ var (
|
||||
kubectl autoscale rc foo --max=5 --cpu-percent=80`))
|
||||
)
|
||||
|
||||
func NewCmdAutoscale(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := &resource.FilenameOptions{}
|
||||
type AutoscaleOptions struct {
|
||||
FilenameOptions *resource.FilenameOptions
|
||||
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
Recorder genericclioptions.Recorder
|
||||
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
ToPrinter func(string) (printers.ResourcePrinter, error)
|
||||
|
||||
Name string
|
||||
Generator string
|
||||
Min int32
|
||||
Max int32
|
||||
CpuPercent int32
|
||||
|
||||
createAnnotation bool
|
||||
args []string
|
||||
enforceNamespace bool
|
||||
namespace string
|
||||
dryRun bool
|
||||
builder *resource.Builder
|
||||
canBeAutoscaled polymorphichelpers.CanBeAutoscaledFunc
|
||||
generatorFunc func(string, *meta.RESTMapping) (kubectl.StructuredGenerator, error)
|
||||
|
||||
HPAClient autoscalingv1client.HorizontalPodAutoscalersGetter
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewAutoscaleOptions(ioStreams genericclioptions.IOStreams) *AutoscaleOptions {
|
||||
return &AutoscaleOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("autoscaled").WithTypeSetter(scheme.Scheme),
|
||||
FilenameOptions: &resource.FilenameOptions{},
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdAutoscale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewAutoscaleOptions(ioStreams)
|
||||
|
||||
validArgs := []string{"deployment", "replicaset", "replicationcontroller"}
|
||||
argAliases := kubectl.ResourceAliases(validArgs)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "autoscale (-f FILENAME | TYPE NAME | TYPE/NAME) [--min=MINPODS] --max=MAXPODS [--cpu-percent=CPU]",
|
||||
@ -58,78 +104,122 @@ func NewCmdAutoscale(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
Long: autoscaleLong,
|
||||
Example: autoscaleExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := RunAutoscale(f, out, cmd, args, options)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: argAliases,
|
||||
ValidArgs: validArgs,
|
||||
}
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmd.Flags().String("generator", cmdutil.HorizontalPodAutoscalerV1GeneratorName, i18n.T("The name of the API generator to use. Currently there is only 1 generator."))
|
||||
cmd.Flags().Int32("min", -1, "The lower limit for the number of pods that can be set by the autoscaler. If it's not specified or negative, the server will apply a default value.")
|
||||
cmd.Flags().Int32("max", -1, "The upper limit for the number of pods that can be set by the autoscaler. Required.")
|
||||
|
||||
// bind flag structs
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmd.Flags().StringVar(&o.Generator, "generator", cmdutil.HorizontalPodAutoscalerV1GeneratorName, i18n.T("The name of the API generator to use. Currently there is only 1 generator."))
|
||||
cmd.Flags().Int32Var(&o.Min, "min", -1, "The lower limit for the number of pods that can be set by the autoscaler. If it's not specified or negative, the server will apply a default value.")
|
||||
cmd.Flags().Int32Var(&o.Max, "max", -1, "The upper limit for the number of pods that can be set by the autoscaler. Required.")
|
||||
cmd.MarkFlagRequired("max")
|
||||
cmd.Flags().Int32("cpu-percent", -1, fmt.Sprintf("The target average CPU utilization (represented as a percent of requested CPU) over all the pods. If it's not specified or negative, a default autoscaling policy will be used."))
|
||||
cmd.Flags().String("name", "", i18n.T("The name for the newly created object. If not specified, the name of the input resource will be used."))
|
||||
cmd.Flags().Int32Var(&o.CpuPercent, "cpu-percent", -1, fmt.Sprintf("The target average CPU utilization (represented as a percent of requested CPU) over all the pods. If it's not specified or negative, a default autoscaling policy will be used."))
|
||||
cmd.Flags().StringVar(&o.Name, "name", "", i18n.T("The name for the newly created object. If not specified, the name of the input resource will be used."))
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
usage := "identifying the resource to autoscale."
|
||||
cmdutil.AddFilenameOptionFlags(cmd, options, usage)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, "identifying the resource to autoscale.")
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions) error {
|
||||
namespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
var err error
|
||||
o.dryRun = cmdutil.GetFlagBool(cmd, "dry-run")
|
||||
o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
|
||||
o.builder = f.NewBuilder()
|
||||
o.canBeAutoscaled = polymorphichelpers.CanBeAutoscaledFn
|
||||
o.args = args
|
||||
o.RecordFlags.Complete(cmd)
|
||||
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// validate flags
|
||||
if err := validateFlags(cmd); err != nil {
|
||||
kubeClient, err := f.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.HPAClient = kubeClient.AutoscalingV1()
|
||||
|
||||
// get the generator
|
||||
o.generatorFunc = func(name string, mapping *meta.RESTMapping) (kubectl.StructuredGenerator, error) {
|
||||
switch o.Generator {
|
||||
case cmdutil.HorizontalPodAutoscalerV1GeneratorName:
|
||||
return &kubectl.HorizontalPodAutoscalerGeneratorV1{
|
||||
Name: name,
|
||||
MinReplicas: o.Min,
|
||||
MaxReplicas: o.Max,
|
||||
CPUPercent: o.CpuPercent,
|
||||
ScaleRefName: name,
|
||||
ScaleRefKind: mapping.GroupVersionKind.Kind,
|
||||
ScaleRefApiVersion: mapping.GroupVersionKind.GroupVersion().String(),
|
||||
}, nil
|
||||
default:
|
||||
return nil, cmdutil.UsageErrorf(cmd, "Generator %s not supported. ", o.Generator)
|
||||
}
|
||||
}
|
||||
|
||||
o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := f.NewBuilder().
|
||||
Internal().
|
||||
o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) {
|
||||
o.PrintFlags.NamePrintFlags.Operation = operation
|
||||
if o.dryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
|
||||
return o.PrintFlags.ToPrinter()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *AutoscaleOptions) Validate() error {
|
||||
if o.Max < 1 {
|
||||
return fmt.Errorf("--max=MAXPODS is required and must be at least 1, max: %d", o.Max)
|
||||
}
|
||||
if o.Max < o.Min {
|
||||
return fmt.Errorf("--max=MAXPODS must be larger or equal to --min=MINPODS, max: %d, min: %d", o.Max, o.Min)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *AutoscaleOptions) Run() error {
|
||||
r := o.builder.
|
||||
WithScheme(legacyscheme.Scheme).
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options).
|
||||
ResourceTypeOrNameArgs(false, args...).
|
||||
NamespaceParam(o.namespace).DefaultNamespace().
|
||||
FilenameParam(o.enforceNamespace, o.FilenameOptions).
|
||||
ResourceTypeOrNameArgs(false, o.args...).
|
||||
Flatten().
|
||||
Do()
|
||||
err = r.Err()
|
||||
if err != nil {
|
||||
if err := r.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
count := 0
|
||||
err = r.Visit(func(info *resource.Info, err error) error {
|
||||
err := r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mapping := info.ResourceMapping()
|
||||
if err := f.CanBeAutoscaled(mapping.GroupVersionKind.GroupKind()); err != nil {
|
||||
if err := o.canBeAutoscaled(mapping.GroupVersionKind.GroupKind()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get the generator
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.HorizontalPodAutoscalerV1GeneratorName:
|
||||
generator = &kubectl.HorizontalPodAutoscalerGeneratorV1{
|
||||
Name: info.Name,
|
||||
MinReplicas: cmdutil.GetFlagInt32(cmd, "min"),
|
||||
MaxReplicas: cmdutil.GetFlagInt32(cmd, "max"),
|
||||
CPUPercent: cmdutil.GetFlagInt32(cmd, "cpu-percent"),
|
||||
ScaleRefName: info.Name,
|
||||
ScaleRefKind: mapping.GroupVersionKind.Kind,
|
||||
ScaleRefApiVersion: mapping.GroupVersionKind.GroupVersion().String(),
|
||||
}
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
generator, err := o.generatorFunc(info.Name, mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate new object
|
||||
@ -137,44 +227,40 @@ func RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hpa, ok := object.(*autoscalingv1.HorizontalPodAutoscaler)
|
||||
if !ok {
|
||||
return fmt.Errorf("generator made %T, not autoscalingv1.HorizontalPodAutoscaler", object)
|
||||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
resourceMapper := &resource.Mapper{
|
||||
ObjectTyper: typer,
|
||||
RESTMapper: mapper,
|
||||
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
|
||||
Decoder: cmdutil.InternalVersionDecoder(),
|
||||
if err := o.Recorder.Record(hpa); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
hpa, err := resourceMapper.InfoForObject(object, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cmdutil.ShouldRecord(cmd, hpa) {
|
||||
if err := cmdutil.RecordChangeCause(hpa.Object, f.Command(cmd, false)); err != nil {
|
||||
|
||||
if o.dryRun {
|
||||
count++
|
||||
|
||||
printer, err := o.ToPrinter("created")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
object = hpa.Object
|
||||
}
|
||||
if cmdutil.GetDryRunFlag(cmd) {
|
||||
return cmdutil.PrintObject(cmd, object, out)
|
||||
return printer.PrintObj(hpa, o.Out)
|
||||
}
|
||||
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), hpa, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
if err := kubectl.CreateOrUpdateAnnotation(o.createAnnotation, hpa, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
object, err = resource.NewHelper(hpa.Client, hpa.Mapping).Create(namespace, false, object)
|
||||
actualHPA, err := o.HPAClient.HorizontalPodAutoscalers(o.namespace).Create(hpa)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
count++
|
||||
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
|
||||
return cmdutil.PrintObject(cmd, object, out)
|
||||
printer, err := o.ToPrinter("autoscaled")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmdutil.PrintSuccess(false, out, info.Object, cmdutil.GetDryRunFlag(cmd), "autoscaled")
|
||||
return nil
|
||||
return printer.PrintObj(actualHPA, o.Out)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@ -184,15 +270,3 @@ func RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateFlags(cmd *cobra.Command) error {
|
||||
errs := []error{}
|
||||
max, min := cmdutil.GetFlagInt32(cmd, "max"), cmdutil.GetFlagInt32(cmd, "min")
|
||||
if max < 1 {
|
||||
errs = append(errs, fmt.Errorf("--max=MAXPODS is required and must be at least 1, max: %d", max))
|
||||
}
|
||||
if max < min {
|
||||
errs = append(errs, fmt.Errorf("--max=MAXPODS must be larger or equal to --min=MINPODS, max: %d, min: %d", max, min))
|
||||
}
|
||||
return utilerrors.NewAggregate(errs)
|
||||
}
|
||||
|
141
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/certificates.go
generated
vendored
141
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/certificates.go
generated
vendored
@ -20,17 +20,24 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/apis/certificates"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewCmdCertificate(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
func NewCmdCertificate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "certificate SUBCOMMAND",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -41,33 +48,61 @@ func NewCmdCertificate(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
},
|
||||
}
|
||||
|
||||
cmd.AddCommand(NewCmdCertificateApprove(f, out))
|
||||
cmd.AddCommand(NewCmdCertificateDeny(f, out))
|
||||
cmd.AddCommand(NewCmdCertificateApprove(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCertificateDeny(f, ioStreams))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
type CertificateOptions struct {
|
||||
resource.FilenameOptions
|
||||
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
csrNames []string
|
||||
outputStyle string
|
||||
|
||||
clientSet internalclientset.Interface
|
||||
builder *resource.Builder
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func (options *CertificateOptions) Complete(cmd *cobra.Command, args []string) error {
|
||||
options.csrNames = args
|
||||
options.outputStyle = cmdutil.GetFlagString(cmd, "output")
|
||||
func (o *CertificateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
o.csrNames = args
|
||||
o.outputStyle = cmdutil.GetFlagString(cmd, "output")
|
||||
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.PrintObj = func(obj runtime.Object, out io.Writer) error {
|
||||
return printer.PrintObj(obj, out)
|
||||
}
|
||||
|
||||
o.builder = f.NewBuilder()
|
||||
o.clientSet, err = f.ClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (options *CertificateOptions) Validate() error {
|
||||
if len(options.csrNames) < 1 && cmdutil.IsFilenameSliceEmpty(options.Filenames) {
|
||||
func (o *CertificateOptions) Validate() error {
|
||||
if len(o.csrNames) < 1 && cmdutil.IsFilenameSliceEmpty(o.Filenames) {
|
||||
return fmt.Errorf("one or more CSRs must be specified as <name> or -f <filename>")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewCmdCertificateApprove(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := CertificateOptions{}
|
||||
func NewCmdCertificateApprove(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := CertificateOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("approved").WithTypeSetter(scheme.Scheme),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "approve (-f FILENAME | NAME)",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -85,19 +120,22 @@ func NewCmdCertificateApprove(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
signed certificate can do.
|
||||
`),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.Complete(cmd, args))
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Validate())
|
||||
cmdutil.CheckErr(options.RunCertificateApprove(f, out))
|
||||
cmdutil.CheckErr(options.RunCertificateApprove(cmdutil.GetFlagBool(cmd, "force")))
|
||||
},
|
||||
}
|
||||
cmdutil.AddOutputFlagsForMutation(cmd)
|
||||
|
||||
options.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmd.Flags().Bool("force", false, "Update the CSR even if it is already approved.")
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, "identifying the resource to update")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (options *CertificateOptions) RunCertificateApprove(f cmdutil.Factory, out io.Writer) error {
|
||||
return options.modifyCertificateCondition(f, out, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, string) {
|
||||
func (o *CertificateOptions) RunCertificateApprove(force bool) error {
|
||||
return o.modifyCertificateCondition(o.builder, o.clientSet, force, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool) {
|
||||
var alreadyApproved bool
|
||||
for _, c := range csr.Status.Conditions {
|
||||
if c.Type == certificates.CertificateApproved {
|
||||
@ -105,7 +143,7 @@ func (options *CertificateOptions) RunCertificateApprove(f cmdutil.Factory, out
|
||||
}
|
||||
}
|
||||
if alreadyApproved {
|
||||
return csr, "approved"
|
||||
return csr, true
|
||||
}
|
||||
csr.Status.Conditions = append(csr.Status.Conditions, certificates.CertificateSigningRequestCondition{
|
||||
Type: certificates.CertificateApproved,
|
||||
@ -113,12 +151,15 @@ func (options *CertificateOptions) RunCertificateApprove(f cmdutil.Factory, out
|
||||
Message: "This CSR was approved by kubectl certificate approve.",
|
||||
LastUpdateTime: metav1.Now(),
|
||||
})
|
||||
return csr, "approved"
|
||||
return csr, false
|
||||
})
|
||||
}
|
||||
|
||||
func NewCmdCertificateDeny(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := CertificateOptions{}
|
||||
func NewCmdCertificateDeny(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := CertificateOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("denied").WithTypeSetter(scheme.Scheme),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "deny (-f FILENAME | NAME)",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -131,19 +172,22 @@ func NewCmdCertificateDeny(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
not to issue a certificate to the requestor.
|
||||
`),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.Complete(cmd, args))
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Validate())
|
||||
cmdutil.CheckErr(options.RunCertificateDeny(f, out))
|
||||
cmdutil.CheckErr(options.RunCertificateDeny(cmdutil.GetFlagBool(cmd, "force")))
|
||||
},
|
||||
}
|
||||
cmdutil.AddOutputFlagsForMutation(cmd)
|
||||
|
||||
options.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmd.Flags().Bool("force", false, "Update the CSR even if it is already denied.")
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, "identifying the resource to update")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (options *CertificateOptions) RunCertificateDeny(f cmdutil.Factory, out io.Writer) error {
|
||||
return options.modifyCertificateCondition(f, out, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, string) {
|
||||
func (o *CertificateOptions) RunCertificateDeny(force bool) error {
|
||||
return o.modifyCertificateCondition(o.builder, o.clientSet, force, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool) {
|
||||
var alreadyDenied bool
|
||||
for _, c := range csr.Status.Conditions {
|
||||
if c.Type == certificates.CertificateDenied {
|
||||
@ -151,7 +195,7 @@ func (options *CertificateOptions) RunCertificateDeny(f cmdutil.Factory, out io.
|
||||
}
|
||||
}
|
||||
if alreadyDenied {
|
||||
return csr, "denied"
|
||||
return csr, true
|
||||
}
|
||||
csr.Status.Conditions = append(csr.Status.Conditions, certificates.CertificateSigningRequestCondition{
|
||||
Type: certificates.CertificateDenied,
|
||||
@ -159,18 +203,14 @@ func (options *CertificateOptions) RunCertificateDeny(f cmdutil.Factory, out io.
|
||||
Message: "This CSR was approved by kubectl certificate deny.",
|
||||
LastUpdateTime: metav1.Now(),
|
||||
})
|
||||
return csr, "denied"
|
||||
return csr, false
|
||||
})
|
||||
}
|
||||
|
||||
func (options *CertificateOptions) modifyCertificateCondition(f cmdutil.Factory, out io.Writer, modify func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, string)) error {
|
||||
func (options *CertificateOptions) modifyCertificateCondition(builder *resource.Builder, clientSet internalclientset.Interface, force bool, modify func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool)) error {
|
||||
var found int
|
||||
c, err := f.ClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r := f.NewBuilder().
|
||||
Internal().
|
||||
r := builder.
|
||||
WithScheme(legacyscheme.Scheme).
|
||||
ContinueOnError().
|
||||
FilenameParam(false, &options.FilenameOptions).
|
||||
ResourceNames("certificatesigningrequest", options.csrNames...).
|
||||
@ -178,24 +218,35 @@ func (options *CertificateOptions) modifyCertificateCondition(f cmdutil.Factory,
|
||||
Flatten().
|
||||
Latest().
|
||||
Do()
|
||||
err = r.Visit(func(info *resource.Info, err error) error {
|
||||
err := r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
csr := info.Object.(*certificates.CertificateSigningRequest)
|
||||
csr, verb := modify(csr)
|
||||
csr, err = c.Certificates().
|
||||
CertificateSigningRequests().
|
||||
UpdateApproval(csr)
|
||||
if err != nil {
|
||||
return err
|
||||
for i := 0; ; i++ {
|
||||
csr := info.Object.(*certificates.CertificateSigningRequest)
|
||||
csr, hasCondition := modify(csr)
|
||||
if !hasCondition || force {
|
||||
csr, err = clientSet.Certificates().
|
||||
CertificateSigningRequests().
|
||||
UpdateApproval(csr)
|
||||
if errors.IsConflict(err) && i < 10 {
|
||||
if err := info.Get(); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
found++
|
||||
cmdutil.PrintSuccess(options.outputStyle == "name", out, info.Object, false, verb)
|
||||
return nil
|
||||
|
||||
return options.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), options.Out)
|
||||
})
|
||||
if found == 0 {
|
||||
fmt.Fprintf(out, "No resources found\n")
|
||||
fmt.Fprintf(options.Out, "No resources found\n")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
59
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/clusterinfo.go
generated
vendored
59
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/clusterinfo.go
generated
vendored
@ -23,10 +23,13 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
|
||||
ct "github.com/daviddengcn/go-colortext"
|
||||
@ -43,42 +46,62 @@ var (
|
||||
kubectl cluster-info`))
|
||||
)
|
||||
|
||||
func NewCmdClusterInfo(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
type ClusterInfoOptions struct {
|
||||
genericclioptions.IOStreams
|
||||
|
||||
Namespace string
|
||||
|
||||
Builder *resource.Builder
|
||||
Client *restclient.Config
|
||||
}
|
||||
|
||||
func NewCmdClusterInfo(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := &ClusterInfoOptions{
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "cluster-info",
|
||||
Short: i18n.T("Display cluster info"),
|
||||
Long: longDescr,
|
||||
Example: clusterinfoExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := RunClusterInfo(f, out, cmd)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
}
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
cmd.AddCommand(NewCmdClusterInfoDump(f, out))
|
||||
cmd.AddCommand(NewCmdClusterInfoDump(f, ioStreams))
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunClusterInfo(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) error {
|
||||
client, err := f.ClientConfig()
|
||||
func (o *ClusterInfoOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
var err error
|
||||
o.Client, err = f.ToRESTConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printService(out, "Kubernetes master", client.Host)
|
||||
|
||||
cmdNamespace := cmdutil.GetFlagString(cmd, "namespace")
|
||||
if cmdNamespace == "" {
|
||||
cmdNamespace = metav1.NamespaceSystem
|
||||
}
|
||||
o.Namespace = cmdNamespace
|
||||
|
||||
o.Builder = f.NewBuilder()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ClusterInfoOptions) Run() error {
|
||||
printService(o.Out, "Kubernetes master", o.Client.Host)
|
||||
|
||||
// TODO use generalized labels once they are implemented (#341)
|
||||
b := f.NewBuilder().
|
||||
Internal().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
b := o.Builder.
|
||||
WithScheme(legacyscheme.Scheme).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
LabelSelectorParam("kubernetes.io/cluster-service=true").
|
||||
ResourceTypeOrNameArgs(false, []string{"services"}...).
|
||||
Latest()
|
||||
err = b.Do().Visit(func(r *resource.Info, err error) error {
|
||||
err := b.Do().Visit(func(r *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -110,10 +133,10 @@ func RunClusterInfo(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) error
|
||||
name = utilnet.JoinSchemeNamePort(scheme, service.ObjectMeta.Name, port.Name)
|
||||
}
|
||||
|
||||
if len(client.GroupVersion.Group) == 0 {
|
||||
link = client.Host + "/api/" + client.GroupVersion.Version + "/namespaces/" + service.ObjectMeta.Namespace + "/services/" + name + "/proxy"
|
||||
if len(o.Client.GroupVersion.Group) == 0 {
|
||||
link = o.Client.Host + "/api/" + o.Client.GroupVersion.Version + "/namespaces/" + service.ObjectMeta.Namespace + "/services/" + name + "/proxy"
|
||||
} else {
|
||||
link = client.Host + "/api/" + client.GroupVersion.Group + "/" + client.GroupVersion.Version + "/namespaces/" + service.ObjectMeta.Namespace + "/services/" + name + "/proxy"
|
||||
link = o.Client.Host + "/api/" + o.Client.GroupVersion.Group + "/" + o.Client.GroupVersion.Version + "/namespaces/" + service.ObjectMeta.Namespace + "/services/" + name + "/proxy"
|
||||
|
||||
}
|
||||
}
|
||||
@ -121,11 +144,11 @@ func RunClusterInfo(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) error
|
||||
if len(name) == 0 {
|
||||
name = service.ObjectMeta.Name
|
||||
}
|
||||
printService(out, name, link)
|
||||
printService(o.Out, name, link)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
out.Write([]byte("\nTo further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.\n"))
|
||||
o.Out.Write([]byte("\nTo further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.\n"))
|
||||
return err
|
||||
|
||||
// TODO consider printing more information about cluster
|
||||
|
134
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/clusterinfo_dump.go
generated
vendored
134
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/clusterinfo_dump.go
generated
vendored
@ -21,31 +21,60 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
type ClusterInfoDumpOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
OutputDir string
|
||||
AllNamespaces bool
|
||||
Namespaces []string
|
||||
|
||||
Timeout time.Duration
|
||||
Clientset internalclientset.Interface
|
||||
Namespace string
|
||||
RESTClientGetter genericclioptions.RESTClientGetter
|
||||
LogsForObject polymorphichelpers.LogsForObjectFunc
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
// NewCmdCreateSecret groups subcommands to create various types of secrets
|
||||
func NewCmdClusterInfoDump(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdClusterInfoDump(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := &ClusterInfoDumpOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("").WithTypeSetter(scheme.Scheme),
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "dump",
|
||||
Short: i18n.T("Dump lots of relevant info for debugging and diagnosis"),
|
||||
Long: dumpLong,
|
||||
Example: dumpExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(dumpClusterInfo(f, cmd, cmdOut))
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
}
|
||||
cmd.Flags().String("output-directory", "", i18n.T("Where to output the files. If empty or '-' uses stdout, otherwise creates a directory hierarchy in that directory"))
|
||||
cmd.Flags().StringSlice("namespaces", []string{}, "A comma separated list of namespaces to dump.")
|
||||
cmd.Flags().Bool("all-namespaces", false, "If true, dump all namespaces. If true, --namespaces is ignored.")
|
||||
cmd.Flags().StringVar(&o.OutputDir, "output-directory", o.OutputDir, i18n.T("Where to output the files. If empty or '-' uses stdout, otherwise creates a directory hierarchy in that directory"))
|
||||
cmd.Flags().StringSliceVar(&o.Namespaces, "namespaces", o.Namespaces, "A comma separated list of namespaces to dump.")
|
||||
cmd.Flags().BoolVar(&o.AllNamespaces, "all-namespaces", o.AllNamespaces, "If true, dump all namespaces. If true, --namespaces is ignored.")
|
||||
cmdutil.AddPodRunningTimeoutFlag(cmd, defaultPodLogsTimeout)
|
||||
return cmd
|
||||
}
|
||||
@ -74,8 +103,7 @@ var (
|
||||
kubectl cluster-info dump --namespaces default,kube-system --output-directory=/path/to/cluster-state`))
|
||||
)
|
||||
|
||||
func setupOutputWriter(cmd *cobra.Command, defaultWriter io.Writer, filename string) io.Writer {
|
||||
dir := cmdutil.GetFlagString(cmd, "output-directory")
|
||||
func setupOutputWriter(dir string, defaultWriter io.Writer, filename string) io.Writer {
|
||||
if len(dir) == 0 || dir == "-" {
|
||||
return defaultWriter
|
||||
}
|
||||
@ -88,31 +116,48 @@ func setupOutputWriter(cmd *cobra.Command, defaultWriter io.Writer, filename str
|
||||
return file
|
||||
}
|
||||
|
||||
func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error {
|
||||
timeout, err := cmdutil.GetPodRunningTimeoutFlag(cmd)
|
||||
if err != nil {
|
||||
return cmdutil.UsageErrorf(cmd, err.Error())
|
||||
}
|
||||
|
||||
clientset, err := f.ClientSet()
|
||||
func (o *ClusterInfoDumpOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printer := &printers.JSONPrinter{}
|
||||
jsonOutputFmt := "json"
|
||||
o.PrintFlags.OutputFormat = &jsonOutputFmt
|
||||
o.PrintObj = printer.PrintObj
|
||||
|
||||
nodes, err := clientset.Core().Nodes().List(metav1.ListOptions{})
|
||||
o.Timeout, err = cmdutil.GetPodRunningTimeoutFlag(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.Clientset, err = f.ClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO this should eventually just be the completed kubeconfigflag struct
|
||||
o.RESTClientGetter = f
|
||||
o.LogsForObject = polymorphichelpers.LogsForObjectFn
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ClusterInfoDumpOptions) Run() error {
|
||||
nodes, err := o.Clientset.Core().Nodes().List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := printer.PrintObj(nodes, setupOutputWriter(cmd, out, "nodes.json")); err != nil {
|
||||
if err := o.PrintObj(nodes, setupOutputWriter(o.OutputDir, o.Out, "nodes.json")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var namespaces []string
|
||||
if cmdutil.GetFlagBool(cmd, "all-namespaces") {
|
||||
namespaceList, err := clientset.Core().Namespaces().List(metav1.ListOptions{})
|
||||
if o.AllNamespaces {
|
||||
namespaceList, err := o.Clientset.Core().Namespaces().List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -120,75 +165,70 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
||||
namespaces = append(namespaces, namespaceList.Items[ix].Name)
|
||||
}
|
||||
} else {
|
||||
namespaces = cmdutil.GetFlagStringSlice(cmd, "namespaces")
|
||||
if len(namespaces) == 0 {
|
||||
cmdNamespace, _, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(o.Namespaces) == 0 {
|
||||
namespaces = []string{
|
||||
metav1.NamespaceSystem,
|
||||
cmdNamespace,
|
||||
o.Namespace,
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, namespace := range namespaces {
|
||||
// TODO: this is repetitive in the extreme. Use reflection or
|
||||
// something to make this a for loop.
|
||||
events, err := clientset.Core().Events(namespace).List(metav1.ListOptions{})
|
||||
events, err := o.Clientset.Core().Events(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := printer.PrintObj(events, setupOutputWriter(cmd, out, path.Join(namespace, "events.json"))); err != nil {
|
||||
if err := o.PrintObj(events, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "events.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rcs, err := clientset.Core().ReplicationControllers(namespace).List(metav1.ListOptions{})
|
||||
rcs, err := o.Clientset.Core().ReplicationControllers(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := printer.PrintObj(rcs, setupOutputWriter(cmd, out, path.Join(namespace, "replication-controllers.json"))); err != nil {
|
||||
if err := o.PrintObj(rcs, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "replication-controllers.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
svcs, err := clientset.Core().Services(namespace).List(metav1.ListOptions{})
|
||||
svcs, err := o.Clientset.Core().Services(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := printer.PrintObj(svcs, setupOutputWriter(cmd, out, path.Join(namespace, "services.json"))); err != nil {
|
||||
if err := o.PrintObj(svcs, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "services.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sets, err := clientset.Extensions().DaemonSets(namespace).List(metav1.ListOptions{})
|
||||
sets, err := o.Clientset.Extensions().DaemonSets(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := printer.PrintObj(sets, setupOutputWriter(cmd, out, path.Join(namespace, "daemonsets.json"))); err != nil {
|
||||
if err := o.PrintObj(sets, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "daemonsets.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
deps, err := clientset.Extensions().Deployments(namespace).List(metav1.ListOptions{})
|
||||
deps, err := o.Clientset.Extensions().Deployments(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := printer.PrintObj(deps, setupOutputWriter(cmd, out, path.Join(namespace, "deployments.json"))); err != nil {
|
||||
if err := o.PrintObj(deps, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "deployments.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rps, err := clientset.Extensions().ReplicaSets(namespace).List(metav1.ListOptions{})
|
||||
rps, err := o.Clientset.Extensions().ReplicaSets(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := printer.PrintObj(rps, setupOutputWriter(cmd, out, path.Join(namespace, "replicasets.json"))); err != nil {
|
||||
if err := o.PrintObj(rps, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "replicasets.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pods, err := clientset.Core().Pods(namespace).List(metav1.ListOptions{})
|
||||
pods, err := o.Clientset.Core().Pods(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := printer.PrintObj(pods, setupOutputWriter(cmd, out, path.Join(namespace, "pods.json"))); err != nil {
|
||||
if err := o.PrintObj(pods, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "pods.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -196,7 +236,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
||||
writer.Write([]byte(fmt.Sprintf("==== START logs for container %s of pod %s/%s ====\n", container.Name, pod.Namespace, pod.Name)))
|
||||
defer writer.Write([]byte(fmt.Sprintf("==== END logs for container %s of pod %s/%s ====\n", container.Name, pod.Namespace, pod.Name)))
|
||||
|
||||
request, err := f.LogsForObject(pod, &api.PodLogOptions{Container: container.Name}, timeout)
|
||||
request, err := o.LogsForObject(o.RESTClientGetter, pod, &api.PodLogOptions{Container: container.Name}, timeout)
|
||||
if err != nil {
|
||||
// Print error and return.
|
||||
writer.Write([]byte(fmt.Sprintf("Create log request error: %s\n", err.Error())))
|
||||
@ -215,19 +255,15 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
||||
for ix := range pods.Items {
|
||||
pod := &pods.Items[ix]
|
||||
containers := pod.Spec.Containers
|
||||
writer := setupOutputWriter(cmd, out, path.Join(namespace, pod.Name, "logs.txt"))
|
||||
writer := setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, pod.Name, "logs.txt"))
|
||||
|
||||
for i := range containers {
|
||||
printContainer(writer, containers[i], pod)
|
||||
}
|
||||
}
|
||||
}
|
||||
dir := cmdutil.GetFlagString(cmd, "output-directory")
|
||||
if len(dir) == 0 {
|
||||
dir = "standard output"
|
||||
}
|
||||
if dir != "-" {
|
||||
fmt.Fprintf(out, "Cluster info dumped to %s\n", dir)
|
||||
if o.OutputDir != "-" {
|
||||
fmt.Fprintf(o.Out, "Cluster info dumped to %s\n", o.OutputDir)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
26
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/clusterinfo_dump_test.go
generated
vendored
26
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/clusterinfo_dump_test.go
generated
vendored
@ -17,25 +17,25 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
func TestSetupOutputWriterNoOp(t *testing.T) {
|
||||
tests := []string{"", "-"}
|
||||
for _, test := range tests {
|
||||
out := &bytes.Buffer{}
|
||||
_, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
f := cmdtesting.NewTestFactory()
|
||||
cmd := NewCmdClusterInfoDump(f, os.Stdout)
|
||||
cmd.Flag("output-directory").Value.Set(test)
|
||||
writer := setupOutputWriter(cmd, out, "/some/file/that/should/be/ignored")
|
||||
if writer != out {
|
||||
t.Errorf("expected: %v, saw: %v", out, writer)
|
||||
defer f.Cleanup()
|
||||
|
||||
writer := setupOutputWriter(test, buf, "/some/file/that/should/be/ignored")
|
||||
if writer != buf {
|
||||
t.Errorf("expected: %v, saw: %v", buf, writer)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -49,13 +49,13 @@ func TestSetupOutputWriterFile(t *testing.T) {
|
||||
fullPath := path.Join(dir, file)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
out := &bytes.Buffer{}
|
||||
_, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
f := cmdtesting.NewTestFactory()
|
||||
cmd := NewCmdClusterInfoDump(f, os.Stdout)
|
||||
cmd.Flag("output-directory").Value.Set(dir)
|
||||
writer := setupOutputWriter(cmd, out, file)
|
||||
if writer == out {
|
||||
t.Errorf("expected: %v, saw: %v", out, writer)
|
||||
defer f.Cleanup()
|
||||
|
||||
writer := setupOutputWriter(dir, buf, file)
|
||||
if writer == buf {
|
||||
t.Errorf("expected: %v, saw: %v", buf, writer)
|
||||
}
|
||||
output := "some data here"
|
||||
writer.Write([]byte(output))
|
||||
|
179
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cmd.go
generated
vendored
179
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cmd.go
generated
vendored
@ -17,22 +17,27 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"k8s.io/apiserver/pkg/util/flag"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
utilflag "k8s.io/apiserver/pkg/util/flag"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/auth"
|
||||
cmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/create"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/get"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/rollout"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/set"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/wait"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -57,9 +62,6 @@ __kubectl_override_flags()
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [ "${w}" == "--all-namespaces" ]; then
|
||||
namespace="--all-namespaces"
|
||||
fi
|
||||
done
|
||||
for var in "${__kubectl_override_flag_list[@]##*-}"; do
|
||||
if eval "test -n \"\$${var}\""; then
|
||||
@ -93,20 +95,27 @@ __kubectl_parse_config()
|
||||
fi
|
||||
}
|
||||
|
||||
# $1 is the name of resource (required)
|
||||
# $2 is template string for kubectl get (optional)
|
||||
__kubectl_parse_get()
|
||||
{
|
||||
local template
|
||||
template="{{ range .items }}{{ .metadata.name }} {{ end }}"
|
||||
template="${2:-"{{ range .items }}{{ .metadata.name }} {{ end }}"}"
|
||||
local kubectl_out
|
||||
if kubectl_out=$(kubectl get $(__kubectl_override_flags) -o template --template="${template}" "$1" 2>/dev/null); then
|
||||
COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
|
||||
COMPREPLY+=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
|
||||
fi
|
||||
}
|
||||
|
||||
__kubectl_get_resource()
|
||||
{
|
||||
if [[ ${#nouns[@]} -eq 0 ]]; then
|
||||
return 1
|
||||
local kubectl_out
|
||||
if kubectl_out=$(kubectl api-resources $(__kubectl_override_flags) -o name --cached --request-timeout=5s --verbs=get 2>/dev/null); then
|
||||
COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
__kubectl_parse_get "${nouns[${#nouns[@]} -1]}"
|
||||
}
|
||||
@ -140,8 +149,8 @@ __kubectl_get_resource_clusterrole()
|
||||
__kubectl_get_containers()
|
||||
{
|
||||
local template
|
||||
template="{{ range .spec.containers }}{{ .name }} {{ end }}"
|
||||
__debug "${FUNCNAME} nouns are ${nouns[*]}"
|
||||
template="{{ range .spec.initContainers }}{{ .name }} {{end}}{{ range .spec.containers }}{{ .name }} {{ end }}"
|
||||
__kubectl_debug "${FUNCNAME} nouns are ${nouns[*]}"
|
||||
|
||||
local len="${#nouns[@]}"
|
||||
if [[ ${len} -ne 1 ]]; then
|
||||
@ -165,10 +174,41 @@ __kubectl_require_pod_and_container()
|
||||
return 0
|
||||
}
|
||||
|
||||
__kubectl_cp()
|
||||
{
|
||||
if [[ $(type -t compopt) = "builtin" ]]; then
|
||||
compopt -o nospace
|
||||
fi
|
||||
|
||||
case "$cur" in
|
||||
/*|[.~]*) # looks like a path
|
||||
return
|
||||
;;
|
||||
*:*) # TODO: complete remote files in the pod
|
||||
return
|
||||
;;
|
||||
*/*) # complete <namespace>/<pod>
|
||||
local template namespace kubectl_out
|
||||
template="{{ range .items }}{{ .metadata.namespace }}/{{ .metadata.name }}: {{ end }}"
|
||||
namespace="${cur%%/*}"
|
||||
if kubectl_out=( $(kubectl get $(__kubectl_override_flags) --namespace "${namespace}" -o template --template="${template}" pods 2>/dev/null) ); then
|
||||
COMPREPLY=( $(compgen -W "${kubectl_out[*]}" -- "${cur}") )
|
||||
fi
|
||||
return
|
||||
;;
|
||||
*) # complete namespaces, pods, and filedirs
|
||||
__kubectl_parse_get "namespace" "{{ range .items }}{{ .metadata.name }}/ {{ end }}"
|
||||
__kubectl_parse_get "pod" "{{ range .items }}{{ .metadata.name }}: {{ end }}"
|
||||
_filedir
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
__custom_func() {
|
||||
case ${last_command} in
|
||||
kubectl_get | kubectl_describe | kubectl_delete | kubectl_label | kubectl_edit | kubectl_patch |\
|
||||
kubectl_annotate | kubectl_expose | kubectl_scale | kubectl_autoscale | kubectl_taint | kubectl_rollout_*)
|
||||
kubectl_annotate | kubectl_expose | kubectl_scale | kubectl_autoscale | kubectl_taint | kubectl_rollout_* |\
|
||||
kubectl_apply_edit-last-applied | kubectl_apply_view-last-applied)
|
||||
__kubectl_get_resource
|
||||
return
|
||||
;;
|
||||
@ -196,6 +236,10 @@ __custom_func() {
|
||||
__kubectl_config_get_clusters
|
||||
return
|
||||
;;
|
||||
kubectl_cp)
|
||||
__kubectl_cp
|
||||
return
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
@ -213,11 +257,11 @@ var (
|
||||
)
|
||||
|
||||
func NewDefaultKubectlCommand() *cobra.Command {
|
||||
return NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr)
|
||||
return NewKubectlCommand(os.Stdin, os.Stdout, os.Stderr)
|
||||
}
|
||||
|
||||
// NewKubectlCommand creates the `kubectl` command and its nested children.
|
||||
func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Command {
|
||||
func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
|
||||
// Parent command to which all subcommands are added.
|
||||
cmds := &cobra.Command{
|
||||
Use: "kubectl",
|
||||
@ -231,8 +275,21 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
|
||||
BashCompletionFunction: bashCompletionFunc,
|
||||
}
|
||||
|
||||
f.BindFlags(cmds.PersistentFlags())
|
||||
f.BindExternalFlags(cmds.PersistentFlags())
|
||||
flags := cmds.PersistentFlags()
|
||||
flags.SetNormalizeFunc(utilflag.WarnWordSepNormalizeFunc) // Warn for "_" flags
|
||||
|
||||
// Normalize all flags that are coming from other packages or pre-configurations
|
||||
// a.k.a. change all "_" to "-". e.g. glog package
|
||||
flags.SetNormalizeFunc(utilflag.WordSepNormalizeFunc)
|
||||
|
||||
kubeConfigFlags := genericclioptions.NewConfigFlags()
|
||||
kubeConfigFlags.AddFlags(flags)
|
||||
matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags)
|
||||
matchVersionKubeConfigFlags.AddFlags(cmds.PersistentFlags())
|
||||
|
||||
cmds.PersistentFlags().AddGoFlagSet(flag.CommandLine)
|
||||
|
||||
f := cmdutil.NewFactory(matchVersionKubeConfigFlags)
|
||||
|
||||
// Sending in 'nil' for the getLanguageFn() results in using
|
||||
// the LANG environment variable.
|
||||
@ -242,77 +299,80 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
|
||||
i18n.LoadTranslations("kubectl", nil)
|
||||
|
||||
// From this point and forward we get warnings on flags that contain "_" separators
|
||||
cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc)
|
||||
cmds.SetGlobalNormalizationFunc(utilflag.WarnWordSepNormalizeFunc)
|
||||
|
||||
ioStreams := genericclioptions.IOStreams{In: in, Out: out, ErrOut: err}
|
||||
|
||||
groups := templates.CommandGroups{
|
||||
{
|
||||
Message: "Basic Commands (Beginner):",
|
||||
Commands: []*cobra.Command{
|
||||
NewCmdCreate(f, out, err),
|
||||
NewCmdExposeService(f, out),
|
||||
NewCmdRun(f, in, out, err),
|
||||
set.NewCmdSet(f, in, out, err),
|
||||
deprecatedAlias("run-container", NewCmdRun(f, in, out, err)),
|
||||
create.NewCmdCreate(f, ioStreams),
|
||||
NewCmdExposeService(f, ioStreams),
|
||||
NewCmdRun(f, ioStreams),
|
||||
set.NewCmdSet(f, ioStreams),
|
||||
deprecatedAlias("run-container", NewCmdRun(f, ioStreams)),
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "Basic Commands (Intermediate):",
|
||||
Commands: []*cobra.Command{
|
||||
resource.NewCmdGet(f, out, err),
|
||||
NewCmdExplain(f, out, err),
|
||||
NewCmdEdit(f, out, err),
|
||||
NewCmdDelete(f, out, err),
|
||||
NewCmdExplain("kubectl", f, ioStreams),
|
||||
get.NewCmdGet("kubectl", f, ioStreams),
|
||||
NewCmdEdit(f, ioStreams),
|
||||
NewCmdDelete(f, ioStreams),
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "Deploy Commands:",
|
||||
Commands: []*cobra.Command{
|
||||
rollout.NewCmdRollout(f, out, err),
|
||||
NewCmdRollingUpdate(f, out),
|
||||
NewCmdScale(f, out, err),
|
||||
NewCmdAutoscale(f, out),
|
||||
rollout.NewCmdRollout(f, ioStreams),
|
||||
NewCmdRollingUpdate(f, ioStreams),
|
||||
NewCmdScale(f, ioStreams),
|
||||
NewCmdAutoscale(f, ioStreams),
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "Cluster Management Commands:",
|
||||
Commands: []*cobra.Command{
|
||||
NewCmdCertificate(f, out),
|
||||
NewCmdClusterInfo(f, out),
|
||||
NewCmdTop(f, out, err),
|
||||
NewCmdCordon(f, out),
|
||||
NewCmdUncordon(f, out),
|
||||
NewCmdDrain(f, out, err),
|
||||
NewCmdTaint(f, out),
|
||||
NewCmdCertificate(f, ioStreams),
|
||||
NewCmdClusterInfo(f, ioStreams),
|
||||
NewCmdTop(f, ioStreams),
|
||||
NewCmdCordon(f, ioStreams),
|
||||
NewCmdUncordon(f, ioStreams),
|
||||
NewCmdDrain(f, ioStreams),
|
||||
NewCmdTaint(f, ioStreams),
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "Troubleshooting and Debugging Commands:",
|
||||
Commands: []*cobra.Command{
|
||||
NewCmdDescribe(f, out, err),
|
||||
NewCmdLogs(f, out, err),
|
||||
NewCmdAttach(f, in, out, err),
|
||||
NewCmdExec(f, in, out, err),
|
||||
NewCmdPortForward(f, out, err),
|
||||
NewCmdProxy(f, out),
|
||||
NewCmdCp(f, out, err),
|
||||
auth.NewCmdAuth(f, out, err),
|
||||
NewCmdDescribe("kubectl", f, ioStreams),
|
||||
NewCmdLogs(f, ioStreams),
|
||||
NewCmdAttach(f, ioStreams),
|
||||
NewCmdExec(f, ioStreams),
|
||||
NewCmdPortForward(f, ioStreams),
|
||||
NewCmdProxy(f, ioStreams),
|
||||
NewCmdCp(f, ioStreams),
|
||||
auth.NewCmdAuth(f, ioStreams),
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "Advanced Commands:",
|
||||
Commands: []*cobra.Command{
|
||||
NewCmdApply("kubectl", f, out, err),
|
||||
NewCmdPatch(f, out),
|
||||
NewCmdReplace(f, out),
|
||||
NewCmdConvert(f, out),
|
||||
NewCmdApply("kubectl", f, ioStreams),
|
||||
NewCmdPatch(f, ioStreams),
|
||||
NewCmdReplace(f, ioStreams),
|
||||
wait.NewCmdWait(f, ioStreams),
|
||||
NewCmdConvert(f, ioStreams),
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "Settings Commands:",
|
||||
Commands: []*cobra.Command{
|
||||
NewCmdLabel(f, out),
|
||||
NewCmdAnnotate(f, out),
|
||||
NewCmdCompletion(out, ""),
|
||||
NewCmdLabel(f, ioStreams),
|
||||
NewCmdAnnotate("kubectl", f, ioStreams),
|
||||
NewCmdCompletion(ioStreams.Out, ""),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -321,7 +381,7 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
|
||||
filters := []string{"options"}
|
||||
|
||||
// Hide the "alpha" subcommand if there are no alpha commands in this build.
|
||||
alpha := NewCmdAlpha(f, in, out, err)
|
||||
alpha := NewCmdAlpha(f, ioStreams)
|
||||
if !alpha.HasSubCommands() {
|
||||
filters = append(filters, alpha.Name())
|
||||
}
|
||||
@ -341,11 +401,12 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
|
||||
}
|
||||
|
||||
cmds.AddCommand(alpha)
|
||||
cmds.AddCommand(cmdconfig.NewCmdConfig(f, clientcmd.NewDefaultPathOptions(), out, err))
|
||||
cmds.AddCommand(NewCmdPlugin(f, in, out, err))
|
||||
cmds.AddCommand(NewCmdVersion(f, out))
|
||||
cmds.AddCommand(NewCmdApiVersions(f, out))
|
||||
cmds.AddCommand(NewCmdOptions(out))
|
||||
cmds.AddCommand(cmdconfig.NewCmdConfig(f, clientcmd.NewDefaultPathOptions(), ioStreams))
|
||||
cmds.AddCommand(NewCmdPlugin(f, ioStreams))
|
||||
cmds.AddCommand(NewCmdVersion(f, ioStreams))
|
||||
cmds.AddCommand(NewCmdApiVersions(f, ioStreams))
|
||||
cmds.AddCommand(NewCmdApiResources(f, ioStreams))
|
||||
cmds.AddCommand(NewCmdOptions(ioStreams.Out))
|
||||
|
||||
return cmds
|
||||
}
|
||||
@ -355,7 +416,7 @@ func runHelp(cmd *cobra.Command, args []string) {
|
||||
}
|
||||
|
||||
func printDeprecationWarning(errOut io.Writer, command, alias string) {
|
||||
fmt.Fprintf(errOut, "%s is DEPRECATED and will be removed in a future version. Use %s instead.", alias, command)
|
||||
fmt.Fprintf(errOut, "%s is DEPRECATED and will be removed in a future version. Use %s instead.\n", alias, command)
|
||||
}
|
||||
|
||||
// deprecatedAlias is intended to be used to create a "wrapper" command around
|
||||
@ -372,3 +433,5 @@ func deprecatedAlias(deprecatedVersion string, cmd *cobra.Command) *cobra.Comman
|
||||
cmd.Hidden = true
|
||||
return cmd
|
||||
}
|
||||
|
||||
var metadataAccessor = meta.NewAccessor()
|
||||
|
234
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cmd_printing_test.go
generated
vendored
Normal file
234
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cmd_printing_test.go
generated
vendored
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
Copyright 2018 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 cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
genericprinters "k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
func TestIllegalPackageSourceCheckerThroughPrintFlags(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
expectInternalObjErr bool
|
||||
output string
|
||||
obj runtime.Object
|
||||
expectedOutput string
|
||||
}{
|
||||
{
|
||||
name: "success printer: object containing package path beginning with forbidden prefix is rejected",
|
||||
expectInternalObjErr: true,
|
||||
obj: internalPod(),
|
||||
},
|
||||
{
|
||||
name: "success printer: object containing package path with no forbidden prefix returns no error",
|
||||
expectInternalObjErr: false,
|
||||
obj: externalPod(),
|
||||
output: "",
|
||||
expectedOutput: "pod/foo succeeded\n",
|
||||
},
|
||||
{
|
||||
name: "name printer: object containing package path beginning with forbidden prefix is rejected",
|
||||
expectInternalObjErr: true,
|
||||
output: "name",
|
||||
obj: internalPod(),
|
||||
},
|
||||
{
|
||||
name: "json printer: object containing package path beginning with forbidden prefix is rejected",
|
||||
expectInternalObjErr: true,
|
||||
output: "json",
|
||||
obj: internalPod(),
|
||||
},
|
||||
{
|
||||
name: "json printer: object containing package path with no forbidden prefix returns no error",
|
||||
expectInternalObjErr: false,
|
||||
obj: externalPod(),
|
||||
output: "json",
|
||||
},
|
||||
{
|
||||
name: "yaml printer: object containing package path beginning with forbidden prefix is rejected",
|
||||
expectInternalObjErr: true,
|
||||
output: "yaml",
|
||||
obj: internalPod(),
|
||||
},
|
||||
{
|
||||
name: "yaml printer: object containing package path with no forbidden prefix returns no error",
|
||||
expectInternalObjErr: false,
|
||||
obj: externalPod(),
|
||||
output: "yaml",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
printFlags := genericclioptions.NewPrintFlags("succeeded").WithTypeSetter(scheme.Scheme)
|
||||
printFlags.OutputFormat = &tc.output
|
||||
|
||||
printer, err := printFlags.ToPrinter()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
|
||||
output := bytes.NewBuffer([]byte{})
|
||||
|
||||
err = printer.PrintObj(tc.obj, output)
|
||||
if err != nil {
|
||||
if !tc.expectInternalObjErr {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
|
||||
if !genericprinters.IsInternalObjectError(err) {
|
||||
t.Fatalf("unexpected error - expecting internal object printer error, got %q", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if tc.expectInternalObjErr {
|
||||
t.Fatalf("expected internal object printer error, but got no error")
|
||||
}
|
||||
|
||||
if len(tc.expectedOutput) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if tc.expectedOutput != output.String() {
|
||||
t.Fatalf("unexpected output: expecting %q, got %q", tc.expectedOutput, output.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIllegalPackageSourceCheckerDirectlyThroughPrinters(t *testing.T) {
|
||||
jsonPathPrinter, err := genericprinters.NewJSONPathPrinter("{ .metadata.name }")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
goTemplatePrinter, err := genericprinters.NewGoTemplatePrinter([]byte("{{ .metadata.name }}"))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
customColumns, err := printers.NewCustomColumnsPrinterFromSpec("NAME:.metadata.name", scheme.Codecs.UniversalDecoder(), true)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
expectInternalObjErr bool
|
||||
printer genericprinters.ResourcePrinter
|
||||
obj runtime.Object
|
||||
expectedOutput string
|
||||
}{
|
||||
{
|
||||
name: "json printer: object containing package path beginning with forbidden prefix is rejected",
|
||||
expectInternalObjErr: true,
|
||||
printer: &genericprinters.JSONPrinter{},
|
||||
obj: internalPod(),
|
||||
},
|
||||
{
|
||||
name: "yaml printer: object containing package path beginning with forbidden prefix is rejected",
|
||||
expectInternalObjErr: true,
|
||||
printer: &genericprinters.YAMLPrinter{},
|
||||
obj: internalPod(),
|
||||
},
|
||||
{
|
||||
name: "jsonpath printer: object containing package path beginning with forbidden prefix is rejected",
|
||||
expectInternalObjErr: true,
|
||||
printer: jsonPathPrinter,
|
||||
obj: internalPod(),
|
||||
},
|
||||
{
|
||||
name: "go-template printer: object containing package path beginning with forbidden prefix is rejected",
|
||||
expectInternalObjErr: true,
|
||||
printer: goTemplatePrinter,
|
||||
obj: internalPod(),
|
||||
},
|
||||
{
|
||||
name: "go-template printer: object containing package path beginning with forbidden prefix is rejected",
|
||||
expectInternalObjErr: true,
|
||||
printer: goTemplatePrinter,
|
||||
obj: internalPod(),
|
||||
},
|
||||
{
|
||||
name: "custom-columns printer: object containing package path beginning with forbidden prefix is rejected",
|
||||
expectInternalObjErr: true,
|
||||
printer: customColumns,
|
||||
obj: internalPod(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
output := bytes.NewBuffer([]byte{})
|
||||
|
||||
err := tc.printer.PrintObj(tc.obj, output)
|
||||
if err != nil {
|
||||
if !tc.expectInternalObjErr {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
|
||||
if !genericprinters.IsInternalObjectError(err) {
|
||||
t.Fatalf("unexpected error - expecting internal object printer error, got %q", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if tc.expectInternalObjErr {
|
||||
t.Fatalf("expected internal object printer error, but got no error")
|
||||
}
|
||||
|
||||
if len(tc.expectedOutput) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if tc.expectedOutput != output.String() {
|
||||
t.Fatalf("unexpected output: expecting %q, got %q", tc.expectedOutput, output.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func internalPod() *api.Pod {
|
||||
return &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "10"},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: api.PodStatus{
|
||||
Phase: api.PodRunning,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func externalPod() *v1.Pod {
|
||||
return &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
}
|
||||
}
|
354
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cmd_test.go
generated
vendored
354
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cmd_test.go
generated
vendored
@ -19,7 +19,6 @@ package cmd
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@ -35,17 +34,11 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/resource"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util/strings"
|
||||
)
|
||||
|
||||
// This init should be removed after switching this command and its tests to user external types.
|
||||
@ -122,44 +115,6 @@ func testData() (*api.PodList, *api.ServiceList, *api.ReplicationControllerList)
|
||||
return pods, svc, rc
|
||||
}
|
||||
|
||||
type testPrinter struct {
|
||||
Objects []runtime.Object
|
||||
Err error
|
||||
GenericPrinter bool
|
||||
}
|
||||
|
||||
func (t *testPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
|
||||
t.Objects = append(t.Objects, obj)
|
||||
fmt.Fprintf(out, "%#v", obj)
|
||||
return t.Err
|
||||
}
|
||||
|
||||
// TODO: implement HandledResources()
|
||||
func (t *testPrinter) HandledResources() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (t *testPrinter) AfterPrint(output io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *testPrinter) IsGeneric() bool {
|
||||
return t.GenericPrinter
|
||||
}
|
||||
|
||||
type testDescriber struct {
|
||||
Name, Namespace string
|
||||
Settings printers.DescriberSettings
|
||||
Output string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (t *testDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (output string, err error) {
|
||||
t.Namespace, t.Name = namespace, name
|
||||
t.Settings = describerSettings
|
||||
return t.Output, t.Err
|
||||
}
|
||||
|
||||
func objBody(codec runtime.Codec, obj runtime.Object) io.ReadCloser {
|
||||
return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, obj))))
|
||||
}
|
||||
@ -176,184 +131,6 @@ func stringBody(body string) io.ReadCloser {
|
||||
return ioutil.NopCloser(bytes.NewReader([]byte(body)))
|
||||
}
|
||||
|
||||
func Example_printMultiContainersReplicationControllerWithWide() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
ctrl := &api.ReplicationController{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
|
||||
},
|
||||
Spec: api.ReplicationControllerSpec{
|
||||
Replicas: 1,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Template: &api.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "foo",
|
||||
Image: "someimage",
|
||||
},
|
||||
{
|
||||
Name: "foo2",
|
||||
Image: "someimage2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: api.ReplicationControllerStatus{
|
||||
Replicas: 1,
|
||||
},
|
||||
}
|
||||
cmd.Flags().Set("output", "wide")
|
||||
err := cmdutil.PrintObject(cmd, ctrl, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
|
||||
// foo 1 1 0 10y foo,foo2 someimage,someimage2 foo=bar
|
||||
}
|
||||
|
||||
func Example_printReplicationController() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
ctrl := &api.ReplicationController{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
|
||||
},
|
||||
Spec: api.ReplicationControllerSpec{
|
||||
Replicas: 1,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Template: &api.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "foo",
|
||||
Image: "someimage",
|
||||
},
|
||||
{
|
||||
Name: "foo2",
|
||||
Image: "someimage",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: api.ReplicationControllerStatus{
|
||||
Replicas: 1,
|
||||
},
|
||||
}
|
||||
err := cmdutil.PrintObject(cmd, ctrl, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// NAME DESIRED CURRENT READY AGE
|
||||
// foo 1 1 0 10y
|
||||
}
|
||||
|
||||
func Example_printPodWithWideFormat() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
nodeName := "kubernetes-node-abcd"
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
pod := &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test1",
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: make([]api.Container, 2),
|
||||
NodeName: nodeName,
|
||||
},
|
||||
Status: api.PodStatus{
|
||||
Phase: "podPhase",
|
||||
ContainerStatuses: []api.ContainerStatus{
|
||||
{Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
|
||||
{RestartCount: 3},
|
||||
},
|
||||
PodIP: "10.1.1.3",
|
||||
},
|
||||
}
|
||||
cmd.Flags().Set("output", "wide")
|
||||
err := cmdutil.PrintObject(cmd, pod, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// NAME READY STATUS RESTARTS AGE IP NODE
|
||||
// test1 1/2 podPhase 6 10y 10.1.1.3 kubernetes-node-abcd
|
||||
}
|
||||
|
||||
func Example_printPodWithShowLabels() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
nodeName := "kubernetes-node-abcd"
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
pod := &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test1",
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
|
||||
Labels: map[string]string{
|
||||
"l1": "key",
|
||||
"l2": "value",
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: make([]api.Container, 2),
|
||||
NodeName: nodeName,
|
||||
},
|
||||
Status: api.PodStatus{
|
||||
Phase: "podPhase",
|
||||
ContainerStatuses: []api.ContainerStatus{
|
||||
{Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
|
||||
{RestartCount: 3},
|
||||
},
|
||||
},
|
||||
}
|
||||
cmd.Flags().Set("show-labels", "true")
|
||||
err := cmdutil.PrintObject(cmd, pod, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// NAME READY STATUS RESTARTS AGE LABELS
|
||||
// test1 1/2 podPhase 6 10y l1=key,l2=value
|
||||
}
|
||||
|
||||
func newAllPhasePodList() *api.PodList {
|
||||
nodeName := "kubernetes-node-abcd"
|
||||
return &api.PodList{
|
||||
@ -446,138 +223,9 @@ func newAllPhasePodList() *api.PodList {
|
||||
}
|
||||
}
|
||||
|
||||
func Example_printPodShowTerminated() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
podList := newAllPhasePodList()
|
||||
// filter pods
|
||||
filterFuncs := tf.DefaultResourceFilterFunc()
|
||||
filterOpts := cmdutil.ExtractCmdPrintOptions(cmd, false)
|
||||
_, filteredPodList, errs := cmdutil.FilterResourceList(podList, filterFuncs, filterOpts)
|
||||
if errs != nil {
|
||||
fmt.Printf("Unexpected filter error: %v\n", errs)
|
||||
}
|
||||
printer, err := cmdutil.PrinterForOptions(cmdutil.ExtractCmdPrintOptions(cmd, false))
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected printer get error: %v\n", errs)
|
||||
}
|
||||
for _, pod := range filteredPodList {
|
||||
err := printer.PrintObj(pod, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
// Output:
|
||||
// NAME READY STATUS RESTARTS AGE
|
||||
// test1 1/2 Pending 6 10y
|
||||
// test2 1/2 Running 6 10y
|
||||
// test3 1/2 Succeeded 6 10y
|
||||
// test4 1/2 Failed 6 10y
|
||||
// test5 1/2 Unknown 6 10y
|
||||
}
|
||||
|
||||
func Example_printPodShowAll() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
cmd := NewCmdRun(tf, os.Stdin, os.Stdout, os.Stderr)
|
||||
podList := newAllPhasePodList()
|
||||
err := cmdutil.PrintObject(cmd, podList, os.Stdout)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// NAME READY STATUS RESTARTS AGE
|
||||
// test1 1/2 Pending 6 10y
|
||||
// test2 1/2 Running 6 10y
|
||||
// test3 1/2 Succeeded 6 10y
|
||||
// test4 1/2 Failed 6 10y
|
||||
// test5 1/2 Unknown 6 10y
|
||||
}
|
||||
|
||||
func Example_printServiceWithLabels() {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: nil,
|
||||
}
|
||||
cmd := resource.NewCmdGet(tf, os.Stdout, os.Stderr)
|
||||
svc := &api.ServiceList{
|
||||
Items: []api.Service{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "svc1",
|
||||
Namespace: "ns1",
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
|
||||
Labels: map[string]string{
|
||||
"l1": "value",
|
||||
},
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Protocol: "UDP", Port: 53},
|
||||
{Protocol: "TCP", Port: 53},
|
||||
},
|
||||
Selector: map[string]string{
|
||||
"s": "magic",
|
||||
},
|
||||
ClusterIP: "10.1.1.1",
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
Status: api.ServiceStatus{},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "svc2",
|
||||
Namespace: "ns2",
|
||||
CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
|
||||
Labels: map[string]string{
|
||||
"l1": "dolla-bill-yall",
|
||||
},
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Protocol: "TCP", Port: 80},
|
||||
{Protocol: "TCP", Port: 8080},
|
||||
},
|
||||
Selector: map[string]string{
|
||||
"s": "kazam",
|
||||
},
|
||||
ClusterIP: "10.1.1.2",
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
Status: api.ServiceStatus{},
|
||||
}},
|
||||
}
|
||||
ld := strings.NewLineDelimiter(os.Stdout, "|")
|
||||
defer ld.Flush()
|
||||
cmd.Flags().Set("label-columns", "l1")
|
||||
err := cmdutil.PrintObject(cmd, svc, ld)
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
}
|
||||
// Output:
|
||||
// |NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE L1|
|
||||
// |svc1 ClusterIP 10.1.1.1 <none> 53/UDP,53/TCP 10y value|
|
||||
// |svc2 ClusterIP 10.1.1.2 <none> 80/TCP,8080/TCP 10y dolla-bill-yall|
|
||||
// ||
|
||||
}
|
||||
|
||||
func TestNormalizationFuncGlobalExistence(t *testing.T) {
|
||||
// This test can be safely deleted when we will not support multiple flag formats
|
||||
root := NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr)
|
||||
root := NewKubectlCommand(os.Stdin, os.Stdout, os.Stderr)
|
||||
|
||||
if root.Parent() != nil {
|
||||
t.Fatal("We expect the root command to be returned")
|
||||
|
4
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/completion.go
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/completion.go
generated
vendored
@ -223,7 +223,7 @@ __kubectl_get_comp_words_by_ref() {
|
||||
__kubectl_filedir() {
|
||||
local RET OLD_IFS w qw
|
||||
|
||||
__debug "_filedir $@ cur=$cur"
|
||||
__kubectl_debug "_filedir $@ cur=$cur"
|
||||
if [[ "$1" = \~* ]]; then
|
||||
# somehow does not work. Maybe, zsh does not call this at all
|
||||
eval echo "$1"
|
||||
@ -240,7 +240,7 @@ __kubectl_filedir() {
|
||||
fi
|
||||
IFS="$OLD_IFS"
|
||||
|
||||
IFS="," __debug "RET=${RET[@]} len=${#RET[@]}"
|
||||
IFS="," __kubectl_debug "RET=${RET[@]} len=${#RET[@]}"
|
||||
|
||||
for w in ${RET[@]}; do
|
||||
if [[ ! "${w}" = "${cur}"* ]]; then
|
||||
|
3
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/BUILD
generated
vendored
3
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/BUILD
generated
vendored
@ -28,8 +28,10 @@ go_library(
|
||||
"//build/visible_to:pkg_kubectl_cmd_config_CONSUMERS",
|
||||
],
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/kubectl/cmd/templates:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions:go_default_library",
|
||||
"//pkg/kubectl/util/i18n:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
@ -64,6 +66,7 @@ go_test(
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
|
||||
|
33
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/config.go
generated
vendored
33
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/config.go
generated
vendored
@ -18,7 +18,6 @@ package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
@ -27,11 +26,12 @@ import (
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
// NewCmdConfig creates a command object for the "config" action, and adds all child commands to it.
|
||||
func NewCmdConfig(f cmdutil.Factory, pathOptions *clientcmd.PathOptions, out, errOut io.Writer) *cobra.Command {
|
||||
func NewCmdConfig(f cmdutil.Factory, pathOptions *clientcmd.PathOptions, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
if len(pathOptions.ExplicitFileFlag) == 0 {
|
||||
pathOptions.ExplicitFileFlag = clientcmd.RecommendedConfigPathFlag
|
||||
}
|
||||
@ -48,25 +48,26 @@ func NewCmdConfig(f cmdutil.Factory, pathOptions *clientcmd.PathOptions, out, er
|
||||
1. If the --` + pathOptions.ExplicitFileFlag + ` flag is set, then only that file is loaded. The flag may only be set once and no merging takes place.
|
||||
2. If $` + pathOptions.EnvVar + ` environment variable is set, then it is used a list of paths (normal path delimitting rules for your system). These paths are merged. When a value is modified, it is modified in the file that defines the stanza. When a value is created, it is created in the first file that exists. If no files in the chain exist, then it creates the last file in the list.
|
||||
3. Otherwise, ` + path.Join("${HOME}", pathOptions.GlobalFileSubpath) + ` is used and no merging takes place.`),
|
||||
Run: cmdutil.DefaultSubCommandRun(errOut),
|
||||
Run: cmdutil.DefaultSubCommandRun(streams.ErrOut),
|
||||
}
|
||||
|
||||
// file paths are common to all sub commands
|
||||
cmd.PersistentFlags().StringVar(&pathOptions.LoadingRules.ExplicitPath, pathOptions.ExplicitFileFlag, pathOptions.LoadingRules.ExplicitPath, "use a particular kubeconfig file")
|
||||
|
||||
cmd.AddCommand(NewCmdConfigView(f, out, errOut, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSetCluster(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSetAuthInfo(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSetContext(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSet(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigUnset(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigCurrentContext(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigUseContext(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigGetContexts(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigGetClusters(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigDeleteCluster(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigDeleteContext(out, errOut, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigRenameContext(out, pathOptions))
|
||||
// TODO(juanvallejo): update all subcommands to work with genericclioptions.IOStreams
|
||||
cmd.AddCommand(NewCmdConfigView(f, streams, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSetCluster(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSetAuthInfo(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSetContext(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSet(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigUnset(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigCurrentContext(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigUseContext(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigGetContexts(streams, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigGetClusters(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigDeleteCluster(streams.Out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigDeleteContext(streams.Out, streams.ErrOut, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigRenameContext(streams.Out, pathOptions))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
11
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/config_test.go
generated
vendored
11
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/config_test.go
generated
vendored
@ -17,7 +17,6 @@ limitations under the License.
|
||||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@ -31,6 +30,7 @@ import (
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
func newRedFederalCowHammerConfig() clientcmdapi.Config {
|
||||
@ -863,15 +863,14 @@ func testConfigCommand(args []string, startingConfig clientcmdapi.Config, t *tes
|
||||
argsToUse = append(argsToUse, "--kubeconfig="+fakeKubeFile.Name())
|
||||
argsToUse = append(argsToUse, args...)
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdConfig(cmdutil.NewFactory(nil), clientcmd.NewDefaultPathOptions(), buf, buf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdConfig(cmdutil.NewFactory(genericclioptions.NewTestConfigFlags()), clientcmd.NewDefaultPathOptions(), streams)
|
||||
// "context" is a global flag, inherited from base kubectl command in the real world
|
||||
cmd.PersistentFlags().String("context", "", "The name of the kubeconfig context to use")
|
||||
cmd.SetArgs(argsToUse)
|
||||
cmd.Execute()
|
||||
|
||||
// outBytes, _ := ioutil.ReadFile(fakeKubeFile.Name())
|
||||
config := clientcmd.GetConfigFromFileOrDie(fakeKubeFile.Name())
|
||||
|
||||
return buf.String(), *config
|
||||
}
|
||||
|
||||
|
2
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/create_authinfo_test.go
generated
vendored
2
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/create_authinfo_test.go
generated
vendored
@ -142,7 +142,7 @@ func TestCreateAuthInfoOptions(t *testing.T) {
|
||||
},
|
||||
{
|
||||
flags: []string{
|
||||
// No name for authinfo provided.
|
||||
// No name for authinfo provided.
|
||||
},
|
||||
wantCompleteErr: true,
|
||||
},
|
||||
|
28
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/get_contexts.go
generated
vendored
28
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/get_contexts.go
generated
vendored
@ -31,6 +31,7 @@ import (
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
@ -41,7 +42,8 @@ type GetContextsOptions struct {
|
||||
nameOnly bool
|
||||
showHeaders bool
|
||||
contextNames []string
|
||||
out io.Writer
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
@ -57,8 +59,12 @@ var (
|
||||
|
||||
// NewCmdConfigGetContexts creates a command object for the "get-contexts" action, which
|
||||
// retrieves one or more contexts from a kubeconfig.
|
||||
func NewCmdConfigGetContexts(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||
options := &GetContextsOptions{configAccess: configAccess}
|
||||
func NewCmdConfigGetContexts(streams genericclioptions.IOStreams, configAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||
options := &GetContextsOptions{
|
||||
configAccess: configAccess,
|
||||
|
||||
IOStreams: streams,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "get-contexts [(-o|--output=)name)]",
|
||||
@ -74,22 +80,22 @@ func NewCmdConfigGetContexts(out io.Writer, configAccess clientcmd.ConfigAccess)
|
||||
cmdutil.CheckErr(fmt.Errorf("output must be one of '' or 'name': %v", outputFormat))
|
||||
}
|
||||
if !supportedOutputTypes.Has(outputFormat) {
|
||||
fmt.Fprintf(out, "--output %v is not available in kubectl config get-contexts; resetting to default output format\n", outputFormat)
|
||||
fmt.Fprintf(options.Out, "--output %v is not available in kubectl config get-contexts; resetting to default output format\n", outputFormat)
|
||||
cmd.Flags().Set("output", "")
|
||||
}
|
||||
cmdutil.CheckErr(options.Complete(cmd, args, out))
|
||||
cmdutil.CheckErr(options.Complete(cmd, args))
|
||||
cmdutil.CheckErr(options.RunGetContexts())
|
||||
},
|
||||
}
|
||||
cmdutil.AddOutputFlags(cmd)
|
||||
cmdutil.AddNoHeadersFlags(cmd)
|
||||
|
||||
cmd.Flags().Bool("no-headers", false, "When using the default or custom-column output format, don't print headers (default print headers).")
|
||||
cmd.Flags().StringP("output", "o", "", "Output format. One of: name")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Complete assigns GetContextsOptions from the args.
|
||||
func (o *GetContextsOptions) Complete(cmd *cobra.Command, args []string, out io.Writer) error {
|
||||
func (o *GetContextsOptions) Complete(cmd *cobra.Command, args []string) error {
|
||||
o.contextNames = args
|
||||
o.out = out
|
||||
o.nameOnly = false
|
||||
if cmdutil.GetFlagString(cmd, "output") == "name" {
|
||||
o.nameOnly = true
|
||||
@ -109,9 +115,9 @@ func (o GetContextsOptions) RunGetContexts() error {
|
||||
return err
|
||||
}
|
||||
|
||||
out, found := o.out.(*tabwriter.Writer)
|
||||
out, found := o.Out.(*tabwriter.Writer)
|
||||
if !found {
|
||||
out = printers.GetNewTabWriter(o.out)
|
||||
out = printers.GetNewTabWriter(o.Out)
|
||||
defer out.Flush()
|
||||
}
|
||||
|
||||
|
6
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/get_contexts_test.go
generated
vendored
6
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/get_contexts_test.go
generated
vendored
@ -17,13 +17,13 @@ limitations under the License.
|
||||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
type getContextsTest struct {
|
||||
@ -157,11 +157,11 @@ func (test getContextsTest) run(t *testing.T) {
|
||||
pathOptions := clientcmd.NewDefaultPathOptions()
|
||||
pathOptions.GlobalFile = fakeKubeFile.Name()
|
||||
pathOptions.EnvVar = ""
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
options := GetContextsOptions{
|
||||
configAccess: pathOptions,
|
||||
}
|
||||
cmd := NewCmdConfigGetContexts(buf, options.configAccess)
|
||||
cmd := NewCmdConfigGetContexts(streams, options.configAccess)
|
||||
if test.nameOnly {
|
||||
cmd.Flags().Set("output", "name")
|
||||
}
|
||||
|
5
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/set.go
generated
vendored
5
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/set.go
generated
vendored
@ -33,11 +33,6 @@ import (
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
const (
|
||||
cannotHaveStepsAfterError = "Cannot have steps after %v. %v are remaining"
|
||||
additionStepRequiredUnlessUnsettingError = "Must have additional steps after %v unless you are unsetting it"
|
||||
)
|
||||
|
||||
type setOptions struct {
|
||||
configAccess clientcmd.ConfigAccess
|
||||
propertyName string
|
||||
|
119
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/view.go
generated
vendored
119
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/view.go
generated
vendored
@ -18,8 +18,6 @@ package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
@ -27,18 +25,28 @@ import (
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
"k8s.io/client-go/tools/clientcmd/api/latest"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
type ViewOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
PrintObject printers.ResourcePrinterFunc
|
||||
|
||||
ConfigAccess clientcmd.ConfigAccess
|
||||
Merge flag.Tristate
|
||||
Flatten bool
|
||||
Minify bool
|
||||
RawByteData bool
|
||||
|
||||
Context string
|
||||
OutputFormat string
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
@ -48,17 +56,25 @@ var (
|
||||
You can use --output jsonpath={...} to extract specific values using a jsonpath expression.`)
|
||||
|
||||
view_example = templates.Examples(`
|
||||
# Show Merged kubeconfig settings.
|
||||
# Show merged kubeconfig settings.
|
||||
kubectl config view
|
||||
|
||||
# Show merged kubeconfig settings and raw certificate data.
|
||||
kubectl config view --raw
|
||||
|
||||
# Get the password for the e2e user
|
||||
kubectl config view -o jsonpath='{.users[?(@.name == "e2e")].user.password}'`)
|
||||
|
||||
defaultOutputFormat = "yaml"
|
||||
)
|
||||
|
||||
func NewCmdConfigView(f cmdutil.Factory, out, errOut io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||
options := &ViewOptions{ConfigAccess: ConfigAccess}
|
||||
// Default to yaml
|
||||
defaultOutputFormat := "yaml"
|
||||
func NewCmdConfigView(f cmdutil.Factory, streams genericclioptions.IOStreams, ConfigAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||
o := &ViewOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("").WithTypeSetter(legacyscheme.Scheme).WithDefaultOutput("yaml"),
|
||||
ConfigAccess: ConfigAccess,
|
||||
|
||||
IOStreams: streams,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "view",
|
||||
@ -66,46 +82,58 @@ func NewCmdConfigView(f cmdutil.Factory, out, errOut io.Writer, ConfigAccess cli
|
||||
Long: view_long,
|
||||
Example: view_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
options.Complete()
|
||||
outputFormat := cmdutil.GetFlagString(cmd, "output")
|
||||
if outputFormat == "wide" {
|
||||
fmt.Fprintf(errOut, "--output wide is not available in kubectl config view; reset to default output format (%s)\n\n", defaultOutputFormat)
|
||||
// TODO: once printing is abstracted, this should be handled at flag declaration time
|
||||
cmd.Flags().Set("output", defaultOutputFormat)
|
||||
}
|
||||
if outputFormat == "" {
|
||||
fmt.Fprintf(errOut, "Reset to default output format (%s) as --output is empty\n", defaultOutputFormat)
|
||||
// TODO: once printing is abstracted, this should be handled at flag declaration time
|
||||
cmd.Flags().Set("output", defaultOutputFormat)
|
||||
}
|
||||
|
||||
printOpts := cmdutil.ExtractCmdPrintOptions(cmd, false)
|
||||
printer, err := cmdutil.PrinterForOptions(printOpts)
|
||||
cmdutil.CheckErr(err)
|
||||
|
||||
cmdutil.CheckErr(options.Run(out, printer))
|
||||
cmdutil.CheckErr(o.Complete(cmd))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
}
|
||||
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmd.Flags().Set("output", defaultOutputFormat)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
options.Merge.Default(true)
|
||||
mergeFlag := cmd.Flags().VarPF(&options.Merge, "merge", "", "Merge the full hierarchy of kubeconfig files")
|
||||
o.Merge.Default(true)
|
||||
mergeFlag := cmd.Flags().VarPF(&o.Merge, "merge", "", "Merge the full hierarchy of kubeconfig files")
|
||||
mergeFlag.NoOptDefVal = "true"
|
||||
cmd.Flags().BoolVar(&options.RawByteData, "raw", false, "Display raw byte data")
|
||||
cmd.Flags().BoolVar(&options.Flatten, "flatten", false, "Flatten the resulting kubeconfig file into self-contained output (useful for creating portable kubeconfig files)")
|
||||
cmd.Flags().BoolVar(&options.Minify, "minify", false, "Remove all information not used by current-context from the output")
|
||||
cmd.Flags().BoolVar(&o.RawByteData, "raw", o.RawByteData, "Display raw byte data")
|
||||
cmd.Flags().BoolVar(&o.Flatten, "flatten", o.Flatten, "Flatten the resulting kubeconfig file into self-contained output (useful for creating portable kubeconfig files)")
|
||||
cmd.Flags().BoolVar(&o.Minify, "minify", o.Minify, "Remove all information not used by current-context from the output")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o ViewOptions) Run(out io.Writer, printer printers.ResourcePrinter) error {
|
||||
func (o *ViewOptions) Complete(cmd *cobra.Command) error {
|
||||
if o.ConfigAccess.IsExplicitFile() {
|
||||
if !o.Merge.Provided() {
|
||||
o.Merge.Set("false")
|
||||
}
|
||||
}
|
||||
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.PrintObject = printer.PrintObj
|
||||
o.Context = cmdutil.GetFlagString(cmd, "context")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o ViewOptions) Validate() error {
|
||||
if !o.Merge.Value() && !o.ConfigAccess.IsExplicitFile() {
|
||||
return errors.New("if merge==false a precise file must to specified")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o ViewOptions) Run() error {
|
||||
config, err := o.loadConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if o.Minify {
|
||||
if len(o.Context) > 0 {
|
||||
config.CurrentContext = o.Context
|
||||
}
|
||||
if err := clientcmdapi.MinifyConfig(config); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -124,22 +152,7 @@ func (o ViewOptions) Run(out io.Writer, printer printers.ResourcePrinter) error
|
||||
return err
|
||||
}
|
||||
|
||||
err = printer.PrintObj(convertedObj, out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ViewOptions) Complete() bool {
|
||||
if o.ConfigAccess.IsExplicitFile() {
|
||||
if !o.Merge.Provided() {
|
||||
o.Merge.Set("false")
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
return o.PrintObject(convertedObj, o.Out)
|
||||
}
|
||||
|
||||
func (o ViewOptions) loadConfig() (*clientcmdapi.Config, error) {
|
||||
@ -152,14 +165,6 @@ func (o ViewOptions) loadConfig() (*clientcmdapi.Config, error) {
|
||||
return config, err
|
||||
}
|
||||
|
||||
func (o ViewOptions) Validate() error {
|
||||
if !o.Merge.Value() && !o.ConfigAccess.IsExplicitFile() {
|
||||
return errors.New("if merge==false a precise file must to specified")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getStartingConfig returns the Config object built from the sources specified by the options, the filename read (only if it was a single file), and an error if something goes wrong
|
||||
func (o *ViewOptions) getStartingConfig() (*clientcmdapi.Config, error) {
|
||||
switch {
|
||||
|
91
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/view_test.go
generated
vendored
91
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/config/view_test.go
generated
vendored
@ -17,7 +17,6 @@ limitations under the License.
|
||||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
@ -25,6 +24,7 @@ import (
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
type viewClusterTest struct {
|
||||
@ -43,19 +43,19 @@ func TestViewCluster(t *testing.T) {
|
||||
"my-cluster": {Server: "https://192.168.0.1:3434"},
|
||||
},
|
||||
Contexts: map[string]*clientcmdapi.Context{
|
||||
"minikube": {AuthInfo: "minikube", Cluster: "minikube"},
|
||||
"my-cluser": {AuthInfo: "mu-cluster", Cluster: "my-cluster"},
|
||||
"minikube": {AuthInfo: "minikube", Cluster: "minikube"},
|
||||
"my-cluster": {AuthInfo: "mu-cluster", Cluster: "my-cluster"},
|
||||
},
|
||||
CurrentContext: "minikube",
|
||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
||||
"minikube": {Token: "minikube-token"},
|
||||
"my-cluser": {Token: "minikube-token"},
|
||||
"minikube": {Token: "minikube-token"},
|
||||
"mu-cluster": {Token: "minikube-token"},
|
||||
},
|
||||
}
|
||||
|
||||
test := viewClusterTest{
|
||||
description: "Testing for kubectl config view",
|
||||
config: conf,
|
||||
flags: []string{},
|
||||
expected: `apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
@ -72,7 +72,7 @@ contexts:
|
||||
- context:
|
||||
cluster: my-cluster
|
||||
user: mu-cluster
|
||||
name: my-cluser
|
||||
name: my-cluster
|
||||
current-context: minikube
|
||||
kind: Config
|
||||
preferences: {}
|
||||
@ -80,10 +80,13 @@ users:
|
||||
- name: minikube
|
||||
user:
|
||||
token: minikube-token
|
||||
- name: my-cluser
|
||||
- name: mu-cluster
|
||||
user:
|
||||
token: minikube-token` + "\n"}
|
||||
token: minikube-token` + "\n",
|
||||
}
|
||||
|
||||
test.run(t)
|
||||
|
||||
}
|
||||
|
||||
func TestViewClusterMinify(t *testing.T) {
|
||||
@ -95,20 +98,27 @@ func TestViewClusterMinify(t *testing.T) {
|
||||
"my-cluster": {Server: "https://192.168.0.1:3434"},
|
||||
},
|
||||
Contexts: map[string]*clientcmdapi.Context{
|
||||
"minikube": {AuthInfo: "minikube", Cluster: "minikube"},
|
||||
"my-cluser": {AuthInfo: "mu-cluster", Cluster: "my-cluster"},
|
||||
"minikube": {AuthInfo: "minikube", Cluster: "minikube"},
|
||||
"my-cluster": {AuthInfo: "mu-cluster", Cluster: "my-cluster"},
|
||||
},
|
||||
CurrentContext: "minikube",
|
||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
||||
"minikube": {Token: "minikube-token"},
|
||||
"my-cluser": {Token: "minikube-token"},
|
||||
"minikube": {Token: "minikube-token"},
|
||||
"mu-cluster": {Token: "minikube-token"},
|
||||
},
|
||||
}
|
||||
test := viewClusterTest{
|
||||
description: "Testing for kubectl config view --minify=true",
|
||||
config: conf,
|
||||
flags: []string{"--minify=true"},
|
||||
expected: `apiVersion: v1
|
||||
|
||||
testCases := []struct {
|
||||
description string
|
||||
config clientcmdapi.Config
|
||||
flags []string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
description: "Testing for kubectl config view --minify=true",
|
||||
config: conf,
|
||||
flags: []string{"--minify=true"},
|
||||
expected: `apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: https://192.168.99.100:8443
|
||||
@ -124,8 +134,41 @@ preferences: {}
|
||||
users:
|
||||
- name: minikube
|
||||
user:
|
||||
token: minikube-token` + "\n"}
|
||||
test.run(t)
|
||||
token: minikube-token` + "\n",
|
||||
},
|
||||
{
|
||||
description: "Testing for kubectl config view --minify=true --context=my-cluster",
|
||||
config: conf,
|
||||
flags: []string{"--minify=true", "--context=my-cluster"},
|
||||
expected: `apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: https://192.168.0.1:3434
|
||||
name: my-cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: my-cluster
|
||||
user: mu-cluster
|
||||
name: my-cluster
|
||||
current-context: my-cluster
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: mu-cluster
|
||||
user:
|
||||
token: minikube-token` + "\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
cmdTest := viewClusterTest{
|
||||
description: test.description,
|
||||
config: test.config,
|
||||
flags: test.flags,
|
||||
expected: test.expected,
|
||||
}
|
||||
cmdTest.run(t)
|
||||
}
|
||||
}
|
||||
|
||||
func (test viewClusterTest) run(t *testing.T) {
|
||||
@ -141,10 +184,12 @@ func (test viewClusterTest) run(t *testing.T) {
|
||||
pathOptions := clientcmd.NewDefaultPathOptions()
|
||||
pathOptions.GlobalFile = fakeKubeFile.Name()
|
||||
pathOptions.EnvVar = ""
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdConfigView(cmdutil.NewFactory(nil), buf, errBuf, pathOptions)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdConfigView(cmdutil.NewFactory(genericclioptions.NewTestConfigFlags()), streams, pathOptions)
|
||||
// "context" is a global flag, inherited from base kubectl command in the real world
|
||||
cmd.Flags().String("context", "", "The name of the kubeconfig context to use")
|
||||
cmd.Flags().Parse(test.flags)
|
||||
|
||||
if err := cmd.Execute(); err != nil {
|
||||
t.Fatalf("unexpected error executing command: %v,kubectl config view flags: %v", err, test.flags)
|
||||
}
|
||||
|
79
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/convert.go
generated
vendored
79
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/convert.go
generated
vendored
@ -18,7 +18,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@ -27,9 +26,10 @@ import (
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
@ -61,8 +61,8 @@ var (
|
||||
|
||||
// NewCmdConvert creates a command object for the generic "convert" action, which
|
||||
// translates the config file into a given version.
|
||||
func NewCmdConvert(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := &ConvertOptions{}
|
||||
func NewCmdConvert(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := NewConvertOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "convert -f FILENAME",
|
||||
@ -71,37 +71,44 @@ func NewCmdConvert(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
Long: convert_long,
|
||||
Example: convert_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := options.Complete(f, out, cmd)
|
||||
cmdutil.CheckErr(err)
|
||||
err = options.RunConvert()
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd))
|
||||
cmdutil.CheckErr(options.RunConvert())
|
||||
},
|
||||
}
|
||||
|
||||
options.PrintFlags.AddFlags(cmd)
|
||||
|
||||
usage := "to need to get converted."
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmd.MarkFlagRequired("filename")
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddNonDeprecatedPrinterFlags(cmd)
|
||||
cmd.Flags().BoolVar(&options.local, "local", true, "If true, convert will NOT try to contact api-server but run locally.")
|
||||
cmd.Flags().BoolVar(&options.local, "local", options.local, "If true, convert will NOT try to contact api-server but run locally.")
|
||||
cmd.Flags().String("output-version", "", i18n.T("Output the formatted object with the given group version (for ex: 'extensions/v1beta1').)"))
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ConvertOptions have the data required to perform the convert operation
|
||||
type ConvertOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
resource.FilenameOptions
|
||||
|
||||
builder *resource.Builder
|
||||
local bool
|
||||
|
||||
out io.Writer
|
||||
printer printers.ResourcePrinter
|
||||
|
||||
genericclioptions.IOStreams
|
||||
specifiedOutputVersion schema.GroupVersion
|
||||
}
|
||||
|
||||
func NewConvertOptions(ioStreams genericclioptions.IOStreams) *ConvertOptions {
|
||||
return &ConvertOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("converted").WithTypeSetter(scheme.Scheme).WithDefaultOutput("yaml"),
|
||||
local: true,
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
// outputVersion returns the preferred output version for generic content (JSON, YAML, or templates)
|
||||
// defaultVersion is never mutated. Nil simply allows clean passing in common usage from client.Config
|
||||
func outputVersion(cmd *cobra.Command) (schema.GroupVersion, error) {
|
||||
@ -114,7 +121,7 @@ func outputVersion(cmd *cobra.Command) (schema.GroupVersion, error) {
|
||||
}
|
||||
|
||||
// Complete collects information required to run Convert command from command line.
|
||||
func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) (err error) {
|
||||
func (o *ConvertOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) (err error) {
|
||||
o.specifiedOutputVersion, err = outputVersion(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -122,7 +129,7 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C
|
||||
|
||||
// build the builder
|
||||
o.builder = f.NewBuilder().
|
||||
Internal().
|
||||
WithScheme(scheme.Scheme).
|
||||
LocalParam(o.local)
|
||||
if !o.local {
|
||||
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
|
||||
@ -132,7 +139,7 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C
|
||||
o.builder.Schema(schema)
|
||||
}
|
||||
|
||||
cmdNamespace, _, err := f.DefaultNamespace()
|
||||
cmdNamespace, _, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -142,20 +149,12 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C
|
||||
Flatten()
|
||||
|
||||
// build the printer
|
||||
o.out = out
|
||||
outputFormat := cmdutil.GetFlagString(cmd, "output")
|
||||
templateFile := cmdutil.GetFlagString(cmd, "template")
|
||||
if len(outputFormat) == 0 {
|
||||
if len(templateFile) == 0 {
|
||||
outputFormat = "yaml"
|
||||
} else {
|
||||
outputFormat = "template"
|
||||
}
|
||||
// TODO: once printing is abstracted, this should be handled at flag declaration time
|
||||
cmd.Flags().Set("output", outputFormat)
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.printer, err = cmdutil.PrinterForOptions(cmdutil.ExtractCmdPrintOptions(cmd, false))
|
||||
return err
|
||||
o.PrintObj = printer.PrintObj
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunConvert implements the generic Convert command
|
||||
@ -182,18 +181,14 @@ func (o *ConvertOptions) RunConvert() error {
|
||||
}
|
||||
|
||||
if meta.IsListType(objects) {
|
||||
_, items, err := cmdutil.FilterResourceList(objects, nil, nil)
|
||||
obj, err := objectListToVersionedObject([]runtime.Object{objects}, o.specifiedOutputVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filteredObj, err := objectListToVersionedObject(items, o.specifiedOutputVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return o.printer.PrintObj(filteredObj, o.out)
|
||||
return o.PrintObj(obj, o.Out)
|
||||
}
|
||||
|
||||
return o.printer.PrintObj(objects, o.out)
|
||||
return o.PrintObj(objects, o.Out)
|
||||
}
|
||||
|
||||
// objectListToVersionedObject receives a list of api objects and a group version
|
||||
@ -204,7 +199,7 @@ func objectListToVersionedObject(objects []runtime.Object, specifiedOutputVersio
|
||||
if !specifiedOutputVersion.Empty() {
|
||||
targetVersions = append(targetVersions, specifiedOutputVersion)
|
||||
}
|
||||
targetVersions = append(targetVersions, scheme.Registry.GroupOrDie(api.GroupName).GroupVersion)
|
||||
targetVersions = append(targetVersions, schema.GroupVersion{Group: "", Version: "v1"})
|
||||
converted, err := tryConvert(scheme.Scheme, objectList, targetVersions...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -231,7 +226,7 @@ func asVersionedObject(infos []*resource.Info, forceList bool, specifiedOutputVe
|
||||
if !specifiedOutputVersion.Empty() {
|
||||
targetVersions = append(targetVersions, specifiedOutputVersion)
|
||||
}
|
||||
targetVersions = append(targetVersions, scheme.Registry.GroupOrDie(api.GroupName).GroupVersion)
|
||||
targetVersions = append(targetVersions, schema.GroupVersion{Group: "", Version: "v1"})
|
||||
|
||||
converted, err := tryConvert(scheme.Scheme, object, targetVersions...)
|
||||
if err != nil {
|
||||
@ -280,14 +275,14 @@ func asVersionedObjects(infos []*resource.Info, specifiedOutputVersion schema.Gr
|
||||
gvks, _, err := scheme.Scheme.ObjectKinds(info.Object)
|
||||
if err == nil {
|
||||
for _, gvk := range gvks {
|
||||
for _, version := range scheme.Registry.EnabledVersionsForGroup(gvk.Group) {
|
||||
for _, version := range scheme.Scheme.PrioritizedVersionsForGroup(gvk.Group) {
|
||||
targetVersions = append(targetVersions, version)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
converted, err := tryConvert(info.Mapping.ObjectConvertor, info.Object, targetVersions...)
|
||||
converted, err := tryConvert(scheme.Scheme, info.Object, targetVersions...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
35
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/convert_test.go
generated
vendored
35
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/convert_test.go
generated
vendored
@ -20,10 +20,12 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/client-go/rest/fake"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
type testcase struct {
|
||||
@ -34,7 +36,6 @@ type testcase struct {
|
||||
}
|
||||
|
||||
type checkField struct {
|
||||
template string
|
||||
expected string
|
||||
}
|
||||
|
||||
@ -46,8 +47,7 @@ func TestConvertObject(t *testing.T) {
|
||||
outputVersion: "extensions/v1beta1",
|
||||
fields: []checkField{
|
||||
{
|
||||
template: "{{.apiVersion}}",
|
||||
expected: "extensions/v1beta1",
|
||||
expected: "apiVersion: extensions/v1beta1",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -57,8 +57,7 @@ func TestConvertObject(t *testing.T) {
|
||||
outputVersion: "apps/v1beta2",
|
||||
fields: []checkField{
|
||||
{
|
||||
template: "{{.apiVersion}}",
|
||||
expected: "apps/v1beta2",
|
||||
expected: "apiVersion: apps/v1beta2",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -68,16 +67,13 @@ func TestConvertObject(t *testing.T) {
|
||||
outputVersion: "autoscaling/v2beta1",
|
||||
fields: []checkField{
|
||||
{
|
||||
template: "{{.apiVersion}}",
|
||||
expected: "autoscaling/v2beta1",
|
||||
expected: "apiVersion: autoscaling/v2beta1",
|
||||
},
|
||||
{
|
||||
template: "{{(index .spec.metrics 0).resource.name}}",
|
||||
expected: "cpu",
|
||||
expected: "name: cpu",
|
||||
},
|
||||
{
|
||||
template: "{{(index .spec.metrics 0).resource.targetAverageUtilization}}",
|
||||
expected: "50",
|
||||
expected: "targetAverageUtilization: 50",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -87,12 +83,10 @@ func TestConvertObject(t *testing.T) {
|
||||
outputVersion: "autoscaling/v1",
|
||||
fields: []checkField{
|
||||
{
|
||||
template: "{{.apiVersion}}",
|
||||
expected: "autoscaling/v1",
|
||||
expected: "apiVersion: autoscaling/v1",
|
||||
},
|
||||
{
|
||||
template: "{{.spec.targetCPUUtilizationPercentage}}",
|
||||
expected: "50",
|
||||
expected: "targetCPUUtilizationPercentage: 50",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -101,23 +95,24 @@ func TestConvertObject(t *testing.T) {
|
||||
for _, tc := range testcases {
|
||||
for _, field := range tc.fields {
|
||||
t.Run(fmt.Sprintf("%s %s", tc.name, field), func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
return nil, nil
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdConvert(tf, buf)
|
||||
cmd := NewCmdConvert(tf, genericclioptions.IOStreams{Out: buf, ErrOut: buf})
|
||||
cmd.Flags().Set("filename", tc.file)
|
||||
cmd.Flags().Set("output-version", tc.outputVersion)
|
||||
cmd.Flags().Set("local", "true")
|
||||
cmd.Flags().Set("output", "go-template="+field.template)
|
||||
cmd.Flags().Set("output", "yaml")
|
||||
cmd.Run(cmd, []string{})
|
||||
if buf.String() != field.expected {
|
||||
if !strings.Contains(buf.String(), field.expected) {
|
||||
t.Errorf("unexpected output when converting %s to %q, expected: %q, but got %q", tc.file, tc.outputVersion, field.expected, buf.String())
|
||||
}
|
||||
})
|
||||
|
205
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cp.go
generated
vendored
205
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cp.go
generated
vendored
@ -18,7 +18,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -28,10 +27,15 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
|
||||
"bytes"
|
||||
|
||||
"github.com/renstrom/dedent"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -61,8 +65,26 @@ var (
|
||||
/file/path for a local file`)
|
||||
)
|
||||
|
||||
type CopyOptions struct {
|
||||
Container string
|
||||
Namespace string
|
||||
|
||||
ClientConfig *restclient.Config
|
||||
Clientset internalclientset.Interface
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewCopyOptions(ioStreams genericclioptions.IOStreams) *CopyOptions {
|
||||
return &CopyOptions{
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCmdCp creates a new Copy command.
|
||||
func NewCmdCp(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.Command {
|
||||
func NewCmdCp(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewCopyOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "cp <file-spec-src> <file-spec-dest>",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -70,10 +92,11 @@ func NewCmdCp(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.Command {
|
||||
Long: "Copy files and directories to and from containers.",
|
||||
Example: cpExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(runCopy(f, cmd, cmdOut, cmdErr, args))
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.Run(args))
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringP("container", "c", "", "Container name. If omitted, the first container in the pod will be chosen")
|
||||
cmd.Flags().StringVarP(&o.Container, "container", "c", o.Container, "Container name. If omitted, the first container in the pod will be chosen")
|
||||
|
||||
return cmd
|
||||
}
|
||||
@ -90,39 +113,60 @@ var (
|
||||
)
|
||||
|
||||
func extractFileSpec(arg string) (fileSpec, error) {
|
||||
pieces := strings.Split(arg, ":")
|
||||
if len(pieces) == 1 {
|
||||
if i := strings.Index(arg, ":"); i == -1 {
|
||||
return fileSpec{File: arg}, nil
|
||||
}
|
||||
if len(pieces) != 2 {
|
||||
// FIXME Kubernetes can't copy files that contain a ':'
|
||||
// character.
|
||||
return fileSpec{}, errFileSpecDoesntMatchFormat
|
||||
}
|
||||
file := pieces[1]
|
||||
|
||||
pieces = strings.Split(pieces[0], "/")
|
||||
if len(pieces) == 1 {
|
||||
return fileSpec{
|
||||
PodName: pieces[0],
|
||||
File: file,
|
||||
}, nil
|
||||
}
|
||||
if len(pieces) == 2 {
|
||||
return fileSpec{
|
||||
PodNamespace: pieces[0],
|
||||
PodName: pieces[1],
|
||||
File: file,
|
||||
}, nil
|
||||
} else if i > 0 {
|
||||
file := arg[i+1:]
|
||||
pod := arg[:i]
|
||||
pieces := strings.Split(pod, "/")
|
||||
if len(pieces) == 1 {
|
||||
return fileSpec{
|
||||
PodName: pieces[0],
|
||||
File: file,
|
||||
}, nil
|
||||
}
|
||||
if len(pieces) == 2 {
|
||||
return fileSpec{
|
||||
PodNamespace: pieces[0],
|
||||
PodName: pieces[1],
|
||||
File: file,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return fileSpec{}, errFileSpecDoesntMatchFormat
|
||||
}
|
||||
|
||||
func runCopy(f cmdutil.Factory, cmd *cobra.Command, out, cmderr io.Writer, args []string) error {
|
||||
func (o *CopyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
var err error
|
||||
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Clientset, err = f.ClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.ClientConfig, err = f.ToRESTConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *CopyOptions) Validate(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 2 {
|
||||
return cmdutil.UsageErrorf(cmd, cpUsageStr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *CopyOptions) Run(args []string) error {
|
||||
if len(args) < 2 {
|
||||
return fmt.Errorf("source and destination are required")
|
||||
}
|
||||
srcSpec, err := extractFileSpec(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
@ -131,24 +175,34 @@ func runCopy(f cmdutil.Factory, cmd *cobra.Command, out, cmderr io.Writer, args
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(srcSpec.PodName) != 0 && len(destSpec.PodName) != 0 {
|
||||
if _, err := os.Stat(args[0]); err == nil {
|
||||
return o.copyToPod(fileSpec{File: args[0]}, destSpec)
|
||||
}
|
||||
return fmt.Errorf("src doesn't exist in local filesystem")
|
||||
}
|
||||
|
||||
if len(srcSpec.PodName) != 0 {
|
||||
return copyFromPod(f, cmd, cmderr, srcSpec, destSpec)
|
||||
return o.copyFromPod(srcSpec, destSpec)
|
||||
}
|
||||
if len(destSpec.PodName) != 0 {
|
||||
return copyToPod(f, cmd, out, cmderr, srcSpec, destSpec)
|
||||
return o.copyToPod(srcSpec, destSpec)
|
||||
}
|
||||
return cmdutil.UsageErrorf(cmd, "One of src or dest must be a remote file specification")
|
||||
return fmt.Errorf("one of src or dest must be a remote file specification")
|
||||
}
|
||||
|
||||
// checkDestinationIsDir receives a destination fileSpec and
|
||||
// determines if the provided destination path exists on the
|
||||
// pod. If the destination path does not exist or is _not_ a
|
||||
// directory, an error is returned with the exit code received.
|
||||
func checkDestinationIsDir(dest fileSpec, f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
func (o *CopyOptions) checkDestinationIsDir(dest fileSpec) error {
|
||||
options := &ExecOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
Out: bytes.NewBuffer([]byte{}),
|
||||
Err: bytes.NewBuffer([]byte{}),
|
||||
IOStreams: genericclioptions.IOStreams{
|
||||
Out: bytes.NewBuffer([]byte{}),
|
||||
ErrOut: bytes.NewBuffer([]byte{}),
|
||||
},
|
||||
|
||||
Namespace: dest.PodNamespace,
|
||||
PodName: dest.PodName,
|
||||
@ -158,21 +212,21 @@ func checkDestinationIsDir(dest fileSpec, f cmdutil.Factory, cmd *cobra.Command)
|
||||
Executor: &DefaultRemoteExecutor{},
|
||||
}
|
||||
|
||||
return execute(f, cmd, options)
|
||||
return o.execute(options)
|
||||
}
|
||||
|
||||
func copyToPod(f cmdutil.Factory, cmd *cobra.Command, stdout, stderr io.Writer, src, dest fileSpec) error {
|
||||
if len(src.File) == 0 {
|
||||
func (o *CopyOptions) copyToPod(src, dest fileSpec) error {
|
||||
if len(src.File) == 0 || len(dest.File) == 0 {
|
||||
return errFileCannotBeEmpty
|
||||
}
|
||||
reader, writer := io.Pipe()
|
||||
|
||||
// strip trailing slash (if any)
|
||||
if strings.HasSuffix(string(dest.File[len(dest.File)-1]), "/") {
|
||||
if dest.File != "/" && strings.HasSuffix(string(dest.File[len(dest.File)-1]), "/") {
|
||||
dest.File = dest.File[:len(dest.File)-1]
|
||||
}
|
||||
|
||||
if err := checkDestinationIsDir(dest, f, cmd); err == nil {
|
||||
if err := o.checkDestinationIsDir(dest); err == nil {
|
||||
// If no error, dest.File was found to be a directory.
|
||||
// Copy specified src into it
|
||||
dest.File = dest.File + "/" + path.Base(src.File)
|
||||
@ -193,9 +247,11 @@ func copyToPod(f cmdutil.Factory, cmd *cobra.Command, stdout, stderr io.Writer,
|
||||
|
||||
options := &ExecOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
In: reader,
|
||||
Out: stdout,
|
||||
Err: stderr,
|
||||
IOStreams: genericclioptions.IOStreams{
|
||||
In: reader,
|
||||
Out: o.Out,
|
||||
ErrOut: o.ErrOut,
|
||||
},
|
||||
Stdin: true,
|
||||
|
||||
Namespace: dest.PodNamespace,
|
||||
@ -205,20 +261,22 @@ func copyToPod(f cmdutil.Factory, cmd *cobra.Command, stdout, stderr io.Writer,
|
||||
Command: cmdArr,
|
||||
Executor: &DefaultRemoteExecutor{},
|
||||
}
|
||||
return execute(f, cmd, options)
|
||||
return o.execute(options)
|
||||
}
|
||||
|
||||
func copyFromPod(f cmdutil.Factory, cmd *cobra.Command, cmderr io.Writer, src, dest fileSpec) error {
|
||||
if len(src.File) == 0 {
|
||||
func (o *CopyOptions) copyFromPod(src, dest fileSpec) error {
|
||||
if len(src.File) == 0 || len(dest.File) == 0 {
|
||||
return errFileCannotBeEmpty
|
||||
}
|
||||
|
||||
reader, outStream := io.Pipe()
|
||||
options := &ExecOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
In: nil,
|
||||
Out: outStream,
|
||||
Err: cmderr,
|
||||
IOStreams: genericclioptions.IOStreams{
|
||||
In: nil,
|
||||
Out: outStream,
|
||||
ErrOut: o.Out,
|
||||
},
|
||||
|
||||
Namespace: src.PodNamespace,
|
||||
PodName: src.PodName,
|
||||
@ -231,13 +289,26 @@ func copyFromPod(f cmdutil.Factory, cmd *cobra.Command, cmderr io.Writer, src, d
|
||||
|
||||
go func() {
|
||||
defer outStream.Close()
|
||||
execute(f, cmd, options)
|
||||
o.execute(options)
|
||||
}()
|
||||
prefix := getPrefix(src.File)
|
||||
prefix = path.Clean(prefix)
|
||||
// remove extraneous path shortcuts - these could occur if a path contained extra "../"
|
||||
// and attempted to navigate beyond "/" in a remote filesystem
|
||||
prefix = stripPathShortcuts(prefix)
|
||||
return untarAll(reader, dest.File, prefix)
|
||||
}
|
||||
|
||||
// stripPathShortcuts removes any leading or trailing "../" from a given path
|
||||
func stripPathShortcuts(p string) string {
|
||||
newPath := path.Clean(p)
|
||||
if len(newPath) > 0 && string(newPath[0]) == "/" {
|
||||
return newPath[1:]
|
||||
}
|
||||
|
||||
return newPath
|
||||
}
|
||||
|
||||
func makeTar(srcPath, destPath string, writer io.Writer) error {
|
||||
// TODO: use compression here?
|
||||
tarWriter := tar.NewWriter(writer)
|
||||
@ -312,6 +383,12 @@ func recursiveTar(srcBase, srcFile, destBase, destFile string, tw *tar.Writer) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// clean prevents path traversals by stripping them out.
|
||||
// This is adapted from https://golang.org/src/net/http/fs.go#L74
|
||||
func clean(fileName string) string {
|
||||
return path.Clean(string(os.PathSeparator) + fileName)
|
||||
}
|
||||
|
||||
func untarAll(reader io.Reader, destFile, prefix string) error {
|
||||
entrySeq := -1
|
||||
|
||||
@ -327,7 +404,7 @@ func untarAll(reader io.Reader, destFile, prefix string) error {
|
||||
}
|
||||
entrySeq++
|
||||
mode := header.FileInfo().Mode()
|
||||
outFileName := path.Join(destFile, header.Name[len(prefix):])
|
||||
outFileName := path.Join(destFile, clean(header.Name[len(prefix):]))
|
||||
baseName := path.Dir(outFileName)
|
||||
if err := os.MkdirAll(baseName, 0755); err != nil {
|
||||
return err
|
||||
@ -346,7 +423,7 @@ func untarAll(reader io.Reader, destFile, prefix string) error {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
outFileName = filepath.Join(outFileName, path.Base(header.Name))
|
||||
outFileName = filepath.Join(outFileName, path.Base(clean(header.Name)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -383,31 +460,17 @@ func getPrefix(file string) string {
|
||||
return strings.TrimLeft(file, "/")
|
||||
}
|
||||
|
||||
func execute(f cmdutil.Factory, cmd *cobra.Command, options *ExecOptions) error {
|
||||
func (o *CopyOptions) execute(options *ExecOptions) error {
|
||||
if len(options.Namespace) == 0 {
|
||||
namespace, _, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options.Namespace = namespace
|
||||
options.Namespace = o.Namespace
|
||||
}
|
||||
|
||||
container := cmdutil.GetFlagString(cmd, "container")
|
||||
if len(container) > 0 {
|
||||
options.ContainerName = container
|
||||
if len(o.Container) > 0 {
|
||||
options.ContainerName = o.Container
|
||||
}
|
||||
|
||||
config, err := f.ClientConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options.Config = config
|
||||
|
||||
clientset, err := f.ClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options.PodClient = clientset.Core()
|
||||
options.Config = o.ClientConfig
|
||||
options.PodClient = o.Clientset.Core()
|
||||
|
||||
if err := options.Validate(); err != nil {
|
||||
return err
|
||||
|
199
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cp_test.go
generated
vendored
199
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/cp_test.go
generated
vendored
@ -21,12 +21,23 @@ import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
type FileType int
|
||||
@ -60,9 +71,18 @@ func TestExtractFileSpec(t *testing.T) {
|
||||
expectedFile: "/some/file",
|
||||
},
|
||||
{
|
||||
spec: "some:bad:spec",
|
||||
spec: ":file:not:exist:in:local:filesystem",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
spec: "namespace/pod/invalid:/some/file",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
spec: "pod:/some/filenamewith:in",
|
||||
expectedPod: "pod",
|
||||
expectedFile: "/some/filenamewith:in",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
spec, err := extractFileSpec(test.spec)
|
||||
@ -422,3 +442,180 @@ func TestTarDestinationName(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadTar(t *testing.T) {
|
||||
dir, err := ioutil.TempDir(os.TempDir(), "dest")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v ", err)
|
||||
t.FailNow()
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
// More or less cribbed from https://golang.org/pkg/archive/tar/#example__minimal
|
||||
var buf bytes.Buffer
|
||||
tw := tar.NewWriter(&buf)
|
||||
var files = []struct {
|
||||
name string
|
||||
body string
|
||||
}{
|
||||
{"/prefix/../../../tmp/foo", "Up to temp"},
|
||||
{"/prefix/foo/bar/../../home/bburns/names.txt", "Down and back"},
|
||||
}
|
||||
for _, file := range files {
|
||||
hdr := &tar.Header{
|
||||
Name: file.name,
|
||||
Mode: 0600,
|
||||
Size: int64(len(file.body)),
|
||||
}
|
||||
if err := tw.WriteHeader(hdr); err != nil {
|
||||
t.Errorf("unexpected error: %v ", err)
|
||||
t.FailNow()
|
||||
}
|
||||
if _, err := tw.Write([]byte(file.body)); err != nil {
|
||||
t.Errorf("unexpected error: %v ", err)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
if err := tw.Close(); err != nil {
|
||||
t.Errorf("unexpected error: %v ", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if err := untarAll(&buf, dir, "/prefix"); err != nil {
|
||||
t.Errorf("unexpected error: %v ", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
_, err := os.Stat(path.Join(dir, path.Clean(file.name[len("/prefix"):])))
|
||||
if err != nil {
|
||||
t.Errorf("Error finding file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestClean(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
cleaned string
|
||||
}{
|
||||
{
|
||||
"../../../tmp/foo",
|
||||
"/tmp/foo",
|
||||
},
|
||||
{
|
||||
"/../../../tmp/foo",
|
||||
"/tmp/foo",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
out := clean(test.input)
|
||||
if out != test.cleaned {
|
||||
t.Errorf("Expected: %s, saw %s", test.cleaned, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyToPod(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
ns := legacyscheme.Codecs
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
responsePod := &v1.Pod{}
|
||||
return &http.Response{StatusCode: http.StatusNotFound, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, responsePod))))}, nil
|
||||
}),
|
||||
}
|
||||
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
ioStreams, _, _, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdCp(tf, ioStreams)
|
||||
|
||||
srcFile, err := ioutil.TempDir("", "test")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
defer os.RemoveAll(srcFile)
|
||||
|
||||
tests := map[string]struct {
|
||||
dest string
|
||||
expectedErr bool
|
||||
}{
|
||||
"copy to directory": {
|
||||
dest: "/tmp/",
|
||||
expectedErr: false,
|
||||
},
|
||||
"copy to root": {
|
||||
dest: "/",
|
||||
expectedErr: false,
|
||||
},
|
||||
"copy to empty file name": {
|
||||
dest: "",
|
||||
expectedErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
opts := NewCopyOptions(ioStreams)
|
||||
src := fileSpec{
|
||||
File: srcFile,
|
||||
}
|
||||
dest := fileSpec{
|
||||
PodNamespace: "pod-ns",
|
||||
PodName: "pod-name",
|
||||
File: test.dest,
|
||||
}
|
||||
opts.Complete(tf, cmd)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
err = opts.copyToPod(src, dest)
|
||||
//If error is NotFound error , it indicates that the
|
||||
//request has been sent correctly.
|
||||
//Treat this as no error.
|
||||
if test.expectedErr && errors.IsNotFound(err) {
|
||||
t.Errorf("expected error but didn't get one")
|
||||
}
|
||||
if !test.expectedErr && !errors.IsNotFound(err) {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
expectedErr bool
|
||||
}{
|
||||
{
|
||||
name: "Validate Succeed",
|
||||
args: []string{"1", "2"},
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "Validate Fail",
|
||||
args: []string{"1", "2", "3"},
|
||||
expectedErr: true,
|
||||
},
|
||||
}
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ioStreams, _, _, _ := genericclioptions.NewTestIOStreams()
|
||||
opts := NewCopyOptions(ioStreams)
|
||||
cmd := NewCmdCp(tf, ioStreams)
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
err := opts.Validate(cmd, test.args)
|
||||
if (err != nil) != test.expectedErr {
|
||||
t.Errorf("expected error: %v, saw: %v, error: %v", test.expectedErr, err != nil, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
362
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create.go
generated
vendored
362
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create.go
generated
vendored
@ -1,362 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 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 cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"net/url"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
type CreateOptions struct {
|
||||
FilenameOptions resource.FilenameOptions
|
||||
Selector string
|
||||
EditBeforeCreate bool
|
||||
Raw string
|
||||
Out io.Writer
|
||||
ErrOut io.Writer
|
||||
}
|
||||
|
||||
var (
|
||||
createLong = templates.LongDesc(i18n.T(`
|
||||
Create a resource from a file or from stdin.
|
||||
|
||||
JSON and YAML formats are accepted.`))
|
||||
|
||||
createExample = templates.Examples(i18n.T(`
|
||||
# Create a pod using the data in pod.json.
|
||||
kubectl create -f ./pod.json
|
||||
|
||||
# Create a pod based on the JSON passed into stdin.
|
||||
cat pod.json | kubectl create -f -
|
||||
|
||||
# Edit the data in docker-registry.yaml in JSON using the v1 API format then create the resource using the edited data.
|
||||
kubectl create -f docker-registry.yaml --edit --output-version=v1 -o json`))
|
||||
)
|
||||
|
||||
func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
options := &CreateOptions{
|
||||
Out: out,
|
||||
ErrOut: errOut,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "create -f FILENAME",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Create a resource from a file or from stdin."),
|
||||
Long: createLong,
|
||||
Example: createExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if cmdutil.IsFilenameSliceEmpty(options.FilenameOptions.Filenames) {
|
||||
defaultRunFunc := cmdutil.DefaultSubCommandRun(errOut)
|
||||
defaultRunFunc(cmd, args)
|
||||
return
|
||||
}
|
||||
cmdutil.CheckErr(options.ValidateArgs(cmd, args))
|
||||
cmdutil.CheckErr(options.RunCreate(f, cmd))
|
||||
},
|
||||
}
|
||||
|
||||
usage := "to use to create the resource"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmd.MarkFlagRequired("filename")
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmd.Flags().BoolVar(&options.EditBeforeCreate, "edit", false, "Edit the API resource before creating")
|
||||
cmd.Flags().Bool("windows-line-endings", runtime.GOOS == "windows",
|
||||
"Only relevant if --edit=true. Defaults to the line ending native to your platform.")
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().StringVar(&options.Raw, "raw", options.Raw, "Raw URI to POST to the server. Uses the transport specified by the kubeconfig file.")
|
||||
|
||||
// create subcommands
|
||||
cmd.AddCommand(NewCmdCreateNamespace(f, out))
|
||||
cmd.AddCommand(NewCmdCreateQuota(f, out))
|
||||
cmd.AddCommand(NewCmdCreateSecret(f, out, errOut))
|
||||
cmd.AddCommand(NewCmdCreateConfigMap(f, out))
|
||||
cmd.AddCommand(NewCmdCreateServiceAccount(f, out))
|
||||
cmd.AddCommand(NewCmdCreateService(f, out, errOut))
|
||||
cmd.AddCommand(NewCmdCreateDeployment(f, out, errOut))
|
||||
cmd.AddCommand(NewCmdCreateClusterRole(f, out))
|
||||
cmd.AddCommand(NewCmdCreateClusterRoleBinding(f, out))
|
||||
cmd.AddCommand(NewCmdCreateRole(f, out))
|
||||
cmd.AddCommand(NewCmdCreateRoleBinding(f, out))
|
||||
cmd.AddCommand(NewCmdCreatePodDisruptionBudget(f, out))
|
||||
cmd.AddCommand(NewCmdCreatePriorityClass(f, out))
|
||||
cmd.AddCommand(NewCmdCreateJob(f, out))
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *CreateOptions) ValidateArgs(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
|
||||
}
|
||||
if len(o.Raw) > 0 {
|
||||
if o.EditBeforeCreate {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --edit are mutually exclusive")
|
||||
}
|
||||
if len(o.FilenameOptions.Filenames) != 1 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw can only use a single local file or stdin")
|
||||
}
|
||||
if strings.Index(o.FilenameOptions.Filenames[0], "http://") == 0 || strings.Index(o.FilenameOptions.Filenames[0], "https://") == 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw cannot read from a url")
|
||||
}
|
||||
if o.FilenameOptions.Recursive {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --recursive are mutually exclusive")
|
||||
}
|
||||
if len(o.Selector) > 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --selector (-l) are mutually exclusive")
|
||||
}
|
||||
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --output are mutually exclusive")
|
||||
}
|
||||
if _, err := url.ParseRequestURI(o.Raw); err != nil {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw must be a valid URL path: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
// raw only makes sense for a single file resource multiple objects aren't likely to do what you want.
|
||||
// the validator enforces this, so
|
||||
if len(o.Raw) > 0 {
|
||||
return o.raw(f)
|
||||
}
|
||||
|
||||
if o.EditBeforeCreate {
|
||||
return RunEditOnCreate(f, o.Out, o.ErrOut, cmd, &o.FilenameOptions)
|
||||
}
|
||||
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := f.NewBuilder().
|
||||
Unstructured().
|
||||
Schema(schema).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
LabelSelectorParam(o.Selector).
|
||||
Flatten().
|
||||
Do()
|
||||
err = r.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dryRun := cmdutil.GetDryRunFlag(cmd)
|
||||
output := cmdutil.GetFlagString(cmd, "output")
|
||||
|
||||
count := 0
|
||||
err = r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
|
||||
if cmdutil.ShouldRecord(cmd, info) {
|
||||
if err := cmdutil.RecordChangeCause(info.Object, f.Command(cmd, false)); err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
}
|
||||
|
||||
if !dryRun {
|
||||
if err := createAndRefresh(info); err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
}
|
||||
|
||||
count++
|
||||
|
||||
shortOutput := output == "name"
|
||||
if len(output) > 0 && !shortOutput {
|
||||
return cmdutil.PrintObject(cmd, info.Object, o.Out)
|
||||
}
|
||||
|
||||
cmdutil.PrintSuccess(shortOutput, o.Out, info.Object, dryRun, "created")
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
return fmt.Errorf("no objects passed to create")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// raw makes a simple HTTP request to the provided path on the server using the default
|
||||
// credentials.
|
||||
func (o *CreateOptions) raw(f cmdutil.Factory) error {
|
||||
restClient, err := f.RESTClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var data io.ReadCloser
|
||||
if o.FilenameOptions.Filenames[0] == "-" {
|
||||
data = os.Stdin
|
||||
} else {
|
||||
data, err = os.Open(o.FilenameOptions.Filenames[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// TODO post content with stream. Right now it ignores body content
|
||||
bytes, err := restClient.Post().RequestURI(o.Raw).Body(data).DoRaw()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(o.Out, "%v", string(bytes))
|
||||
return nil
|
||||
}
|
||||
|
||||
func RunEditOnCreate(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, options *resource.FilenameOptions) error {
|
||||
editOptions := &editor.EditOptions{
|
||||
EditMode: editor.EditBeforeCreateMode,
|
||||
FilenameOptions: *options,
|
||||
ValidateOptions: cmdutil.ValidateOptions{
|
||||
EnableValidation: cmdutil.GetFlagBool(cmd, "validate"),
|
||||
},
|
||||
Output: cmdutil.GetFlagString(cmd, "output"),
|
||||
WindowsLineEndings: cmdutil.GetFlagBool(cmd, "windows-line-endings"),
|
||||
ApplyAnnotation: cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag),
|
||||
Record: cmdutil.GetFlagBool(cmd, "record"),
|
||||
ChangeCause: f.Command(cmd, false),
|
||||
Include3rdParty: cmdutil.GetFlagBool(cmd, "include-extended-apis"),
|
||||
}
|
||||
err := editOptions.Complete(f, out, errOut, []string{}, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return editOptions.Run()
|
||||
}
|
||||
|
||||
// createAndRefresh creates an object from input info and refreshes info with that object
|
||||
func createAndRefresh(info *resource.Info) error {
|
||||
obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info.Refresh(obj, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
// NameFromCommandArgs is a utility function for commands that assume the first argument is a resource name
|
||||
func NameFromCommandArgs(cmd *cobra.Command, args []string) (string, error) {
|
||||
if len(args) != 1 {
|
||||
return "", cmdutil.UsageErrorf(cmd, "exactly one NAME is required, got %d", len(args))
|
||||
}
|
||||
return args[0], nil
|
||||
}
|
||||
|
||||
// CreateSubcommandOptions is an options struct to support create subcommands
|
||||
type CreateSubcommandOptions struct {
|
||||
// Name of resource being created
|
||||
Name string
|
||||
// StructuredGenerator is the resource generator for the object being created
|
||||
StructuredGenerator kubectl.StructuredGenerator
|
||||
// DryRun is true if the command should be simulated but not run against the server
|
||||
DryRun bool
|
||||
OutputFormat string
|
||||
}
|
||||
|
||||
// RunCreateSubcommand executes a create subcommand using the specified options
|
||||
func RunCreateSubcommand(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *CreateSubcommandOptions) error {
|
||||
namespace, nsOverriden, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj, err := options.StructuredGenerator.StructuredGenerate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mapper, typer := f.Object()
|
||||
gvks, _, err := typer.ObjectKinds(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gvk := gvks[0]
|
||||
mapping, err := mapper.RESTMapping(schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := f.ClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resourceMapper := &resource.Mapper{
|
||||
ObjectTyper: typer,
|
||||
RESTMapper: mapper,
|
||||
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
|
||||
}
|
||||
info, err := resourceMapper.InfoForObject(obj, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
obj = info.Object
|
||||
|
||||
if !options.DryRun {
|
||||
obj, err = resource.NewHelper(client, mapping).Create(namespace, false, info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if meta, err := meta.Accessor(obj); err == nil && nsOverriden {
|
||||
meta.SetNamespace(namespace)
|
||||
}
|
||||
}
|
||||
|
||||
if useShortOutput := options.OutputFormat == "name"; useShortOutput || len(options.OutputFormat) == 0 {
|
||||
cmdutil.PrintSuccess(useShortOutput, out, info.Object, options.DryRun, "created")
|
||||
return nil
|
||||
}
|
||||
|
||||
return cmdutil.PrintObject(cmd, obj, out)
|
||||
}
|
117
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create/BUILD
generated
vendored
Normal file
117
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create/BUILD
generated
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"create.go",
|
||||
"create_clusterrole.go",
|
||||
"create_clusterrolebinding.go",
|
||||
"create_configmap.go",
|
||||
"create_deployment.go",
|
||||
"create_job.go",
|
||||
"create_namespace.go",
|
||||
"create_pdb.go",
|
||||
"create_priorityclass.go",
|
||||
"create_quota.go",
|
||||
"create_role.go",
|
||||
"create_rolebinding.go",
|
||||
"create_secret.go",
|
||||
"create_service.go",
|
||||
"create_serviceaccount.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/create",
|
||||
visibility = ["//build/visible_to:pkg_kubectl_cmd_create_CONSUMERS"],
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/cmd/templates:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/editor:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/resource:go_default_library",
|
||||
"//pkg/kubectl/scheme:go_default_library",
|
||||
"//pkg/kubectl/util/i18n:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
"//vendor/k8s.io/api/batch/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/batch/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
|
||||
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/batch/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/rbac/v1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"create_clusterrole_test.go",
|
||||
"create_clusterrolebinding_test.go",
|
||||
"create_configmap_test.go",
|
||||
"create_deployment_test.go",
|
||||
"create_job_test.go",
|
||||
"create_namespace_test.go",
|
||||
"create_pdb_test.go",
|
||||
"create_priorityclass_test.go",
|
||||
"create_quota_test.go",
|
||||
"create_role_test.go",
|
||||
"create_rolebinding_test.go",
|
||||
"create_secret_test.go",
|
||||
"create_service_test.go",
|
||||
"create_serviceaccount_test.go",
|
||||
"create_test.go",
|
||||
],
|
||||
data = [
|
||||
"//test/e2e/testing-manifests:all-srcs",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/api/testing:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/cmd/testing:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/resource:go_default_library",
|
||||
"//pkg/kubectl/scheme:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/k8s.io/api/batch/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/batch/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing: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"],
|
||||
)
|
451
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create/create.go
generated
vendored
Normal file
451
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create/create.go
generated
vendored
Normal file
@ -0,0 +1,451 @@
|
||||
/*
|
||||
Copyright 2014 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 create
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
kruntime "k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
type CreateOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
|
||||
DryRun bool
|
||||
|
||||
FilenameOptions resource.FilenameOptions
|
||||
Selector string
|
||||
EditBeforeCreate bool
|
||||
Raw string
|
||||
|
||||
Recorder genericclioptions.Recorder
|
||||
PrintObj func(obj kruntime.Object) error
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
createLong = templates.LongDesc(i18n.T(`
|
||||
Create a resource from a file or from stdin.
|
||||
|
||||
JSON and YAML formats are accepted.`))
|
||||
|
||||
createExample = templates.Examples(i18n.T(`
|
||||
# Create a pod using the data in pod.json.
|
||||
kubectl create -f ./pod.json
|
||||
|
||||
# Create a pod based on the JSON passed into stdin.
|
||||
cat pod.json | kubectl create -f -
|
||||
|
||||
# Edit the data in docker-registry.yaml in JSON then create the resource using the edited data.
|
||||
kubectl create -f docker-registry.yaml --edit -o json`))
|
||||
)
|
||||
|
||||
func NewCreateOptions(ioStreams genericclioptions.IOStreams) *CreateOptions {
|
||||
return &CreateOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdCreate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewCreateOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "create -f FILENAME",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Create a resource from a file or from stdin."),
|
||||
Long: createLong,
|
||||
Example: createExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames) {
|
||||
defaultRunFunc := cmdutil.DefaultSubCommandRun(ioStreams.ErrOut)
|
||||
defaultRunFunc(cmd, args)
|
||||
return
|
||||
}
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.ValidateArgs(cmd, args))
|
||||
cmdutil.CheckErr(o.RunCreate(f, cmd))
|
||||
},
|
||||
}
|
||||
|
||||
// bind flag structs
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
|
||||
usage := "to use to create the resource"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||
cmd.MarkFlagRequired("filename")
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmd.Flags().BoolVar(&o.EditBeforeCreate, "edit", o.EditBeforeCreate, "Edit the API resource before creating")
|
||||
cmd.Flags().Bool("windows-line-endings", runtime.GOOS == "windows",
|
||||
"Only relevant if --edit=true. Defaults to the line ending native to your platform.")
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().StringVar(&o.Raw, "raw", o.Raw, "Raw URI to POST to the server. Uses the transport specified by the kubeconfig file.")
|
||||
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
// create subcommands
|
||||
cmd.AddCommand(NewCmdCreateNamespace(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateQuota(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateSecret(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateConfigMap(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateServiceAccount(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateService(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateDeployment(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateClusterRole(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateClusterRoleBinding(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateRole(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateRoleBinding(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreatePodDisruptionBudget(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreatePriorityClass(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateJob(f, ioStreams))
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *CreateOptions) ValidateArgs(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
|
||||
}
|
||||
if len(o.Raw) > 0 {
|
||||
if o.EditBeforeCreate {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --edit are mutually exclusive")
|
||||
}
|
||||
if len(o.FilenameOptions.Filenames) != 1 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw can only use a single local file or stdin")
|
||||
}
|
||||
if strings.Index(o.FilenameOptions.Filenames[0], "http://") == 0 || strings.Index(o.FilenameOptions.Filenames[0], "https://") == 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw cannot read from a url")
|
||||
}
|
||||
if o.FilenameOptions.Recursive {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --recursive are mutually exclusive")
|
||||
}
|
||||
if len(o.Selector) > 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --selector (-l) are mutually exclusive")
|
||||
}
|
||||
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --output are mutually exclusive")
|
||||
}
|
||||
if _, err := url.ParseRequestURI(o.Raw); err != nil {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw must be a valid URL path: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *CreateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
var err error
|
||||
|
||||
o.RecordFlags.Complete(cmd)
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.PrintObj = func(obj kruntime.Object) error {
|
||||
return printer.PrintObj(obj, o.Out)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
// raw only makes sense for a single file resource multiple objects aren't likely to do what you want.
|
||||
// the validator enforces this, so
|
||||
if len(o.Raw) > 0 {
|
||||
return o.raw(f)
|
||||
}
|
||||
|
||||
if o.EditBeforeCreate {
|
||||
return RunEditOnCreate(f, o.RecordFlags, o.IOStreams, cmd, &o.FilenameOptions)
|
||||
}
|
||||
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := f.NewBuilder().
|
||||
Unstructured().
|
||||
Schema(schema).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
LabelSelectorParam(o.Selector).
|
||||
Flatten().
|
||||
Do()
|
||||
err = r.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
count := 0
|
||||
err = r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info.Object, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
|
||||
if err := o.Recorder.Record(info.Object); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
|
||||
if !o.DryRun {
|
||||
if err := createAndRefresh(info); err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
}
|
||||
|
||||
count++
|
||||
|
||||
return o.PrintObj(info.Object)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
return fmt.Errorf("no objects passed to create")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// raw makes a simple HTTP request to the provided path on the server using the default
|
||||
// credentials.
|
||||
func (o *CreateOptions) raw(f cmdutil.Factory) error {
|
||||
restClient, err := f.RESTClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var data io.ReadCloser
|
||||
if o.FilenameOptions.Filenames[0] == "-" {
|
||||
data = os.Stdin
|
||||
} else {
|
||||
data, err = os.Open(o.FilenameOptions.Filenames[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// TODO post content with stream. Right now it ignores body content
|
||||
result := restClient.Post().RequestURI(o.Raw).Body(data).Do()
|
||||
if err := result.Error(); err != nil {
|
||||
return err
|
||||
}
|
||||
body, err := result.Raw()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(o.Out, "%v", string(body))
|
||||
return nil
|
||||
}
|
||||
|
||||
func RunEditOnCreate(f cmdutil.Factory, recordFlags *genericclioptions.RecordFlags, ioStreams genericclioptions.IOStreams, cmd *cobra.Command, options *resource.FilenameOptions) error {
|
||||
editOptions := editor.NewEditOptions(editor.EditBeforeCreateMode, ioStreams)
|
||||
editOptions.FilenameOptions = *options
|
||||
editOptions.ValidateOptions = cmdutil.ValidateOptions{
|
||||
EnableValidation: cmdutil.GetFlagBool(cmd, "validate"),
|
||||
}
|
||||
editOptions.Output = cmdutil.GetFlagString(cmd, "output")
|
||||
editOptions.ApplyAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
|
||||
editOptions.RecordFlags = recordFlags
|
||||
|
||||
err := editOptions.Complete(f, []string{}, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return editOptions.Run()
|
||||
}
|
||||
|
||||
// createAndRefresh creates an object from input info and refreshes info with that object
|
||||
func createAndRefresh(info *resource.Info) error {
|
||||
obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info.Refresh(obj, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
// NameFromCommandArgs is a utility function for commands that assume the first argument is a resource name
|
||||
func NameFromCommandArgs(cmd *cobra.Command, args []string) (string, error) {
|
||||
if len(args) != 1 {
|
||||
return "", cmdutil.UsageErrorf(cmd, "exactly one NAME is required, got %d", len(args))
|
||||
}
|
||||
return args[0], nil
|
||||
}
|
||||
|
||||
// CreateSubcommandOptions is an options struct to support create subcommands
|
||||
type CreateSubcommandOptions struct {
|
||||
// PrintFlags holds options necessary for obtaining a printer
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
// Name of resource being created
|
||||
Name string
|
||||
// StructuredGenerator is the resource generator for the object being created
|
||||
StructuredGenerator kubectl.StructuredGenerator
|
||||
// DryRun is true if the command should be simulated but not run against the server
|
||||
DryRun bool
|
||||
CreateAnnotation bool
|
||||
|
||||
Namespace string
|
||||
EnforceNamespace bool
|
||||
|
||||
Mapper meta.RESTMapper
|
||||
DynamicClient dynamic.Interface
|
||||
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewCreateSubcommandOptions(ioStreams genericclioptions.IOStreams) *CreateSubcommandOptions {
|
||||
return &CreateSubcommandOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *CreateSubcommandOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string, generator kubectl.StructuredGenerator) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Name = name
|
||||
o.StructuredGenerator = generator
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
|
||||
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.PrintObj = func(obj kruntime.Object, out io.Writer) error {
|
||||
return printer.PrintObj(obj, out)
|
||||
}
|
||||
|
||||
o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.DynamicClient, err = f.DynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Mapper, err = f.ToRESTMapper()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunCreateSubcommand executes a create subcommand using the specified options
|
||||
func (o *CreateSubcommandOptions) Run() error {
|
||||
obj, err := o.StructuredGenerator.StructuredGenerate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !o.DryRun {
|
||||
// create subcommands have compiled knowledge of things they create, so type them directly
|
||||
gvks, _, err := legacyscheme.Scheme.ObjectKinds(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gvk := gvks[0]
|
||||
mapping, err := o.Mapper.RESTMapping(schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := kubectl.CreateOrUpdateAnnotation(o.CreateAnnotation, obj, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
asUnstructured := &unstructured.Unstructured{}
|
||||
|
||||
if err := legacyscheme.Scheme.Convert(obj, asUnstructured, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if mapping.Scope.Name() == meta.RESTScopeNameRoot {
|
||||
o.Namespace = ""
|
||||
}
|
||||
actualObject, err := o.DynamicClient.Resource(mapping.Resource).Namespace(o.Namespace).Create(asUnstructured)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// ensure we pass a versioned object to the printer
|
||||
obj = actualObject
|
||||
} else {
|
||||
if meta, err := meta.Accessor(obj); err == nil && o.EnforceNamespace {
|
||||
meta.SetNamespace(o.Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
return o.PrintObj(obj, o.Out)
|
||||
}
|
@ -14,18 +14,20 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilflag "k8s.io/apiserver/pkg/util/flag"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -38,7 +40,7 @@ var (
|
||||
kubectl create clusterrole pod-reader --verb=get,list,watch --resource=pods
|
||||
|
||||
# Create a ClusterRole named "pod-reader" with ResourceName specified
|
||||
kubectl create clusterrole pod-reader --verb=get,list,watch --resource=pods --resource-name=readablepod --resource-name=anotherpod
|
||||
kubectl create clusterrole pod-reader --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod
|
||||
|
||||
# Create a ClusterRole named "foo" with API Group specified
|
||||
kubectl create clusterrole foo --verb=get,list,watch --resource=rs.extensions
|
||||
@ -47,7 +49,10 @@ var (
|
||||
kubectl create clusterrole foo --verb=get,list,watch --resource=pods,pods/status
|
||||
|
||||
# Create a ClusterRole name "foo" with NonResourceURL specified
|
||||
kubectl create clusterrole "foo" --verb=get --non-resource-url=/logs/*`))
|
||||
kubectl create clusterrole "foo" --verb=get --non-resource-url=/logs/*
|
||||
|
||||
# Create a ClusterRole name "monitoring" with AggregationRule specified
|
||||
kubectl create clusterrole monitoring --aggregation-rule="rbac.example.com/aggregate-to-monitoring=true"`))
|
||||
|
||||
// Valid nonResource verb list for validation.
|
||||
validNonResourceVerbs = []string{"*", "get", "post", "put", "delete", "patch", "head", "options"}
|
||||
@ -56,14 +61,14 @@ var (
|
||||
type CreateClusterRoleOptions struct {
|
||||
*CreateRoleOptions
|
||||
NonResourceURLs []string
|
||||
AggregationRule map[string]string
|
||||
}
|
||||
|
||||
// ClusterRole is a command to ease creating ClusterRoles.
|
||||
func NewCmdCreateClusterRole(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateClusterRole(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
c := &CreateClusterRoleOptions{
|
||||
CreateRoleOptions: &CreateRoleOptions{
|
||||
Out: cmdOut,
|
||||
},
|
||||
CreateRoleOptions: NewCreateRoleOptions(ioStreams),
|
||||
AggregationRule: map[string]string{},
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "clusterrole NAME --verb=verb --resource=resource.group [--resource-name=resourcename] [--dry-run]",
|
||||
@ -77,14 +82,17 @@ func NewCmdCreateClusterRole(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command
|
||||
cmdutil.CheckErr(c.RunCreateRole())
|
||||
},
|
||||
}
|
||||
|
||||
c.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmd.Flags().StringSliceVar(&c.Verbs, "verb", []string{}, "Verb that applies to the resources contained in the rule")
|
||||
cmd.Flags().StringSliceVar(&c.NonResourceURLs, "non-resource-url", []string{}, "A partial url that user should have access to.")
|
||||
cmd.Flags().StringSliceVar(&c.Verbs, "verb", c.Verbs, "Verb that applies to the resources contained in the rule")
|
||||
cmd.Flags().StringSliceVar(&c.NonResourceURLs, "non-resource-url", c.NonResourceURLs, "A partial url that user should have access to.")
|
||||
cmd.Flags().StringSlice("resource", []string{}, "Resource that the rule applies to")
|
||||
cmd.Flags().StringArrayVar(&c.ResourceNames, "resource-name", []string{}, "Resource in the white list that the rule applies to, repeat this flag for multiple items")
|
||||
cmd.Flags().StringArrayVar(&c.ResourceNames, "resource-name", c.ResourceNames, "Resource in the white list that the rule applies to, repeat this flag for multiple items")
|
||||
cmd.Flags().Var(utilflag.NewMapStringString(&c.AggregationRule), "aggregation-rule", "An aggregation label selector for combining ClusterRoles.")
|
||||
|
||||
return cmd
|
||||
}
|
||||
@ -107,6 +115,13 @@ func (c *CreateClusterRoleOptions) Validate() error {
|
||||
return fmt.Errorf("name must be specified")
|
||||
}
|
||||
|
||||
if len(c.AggregationRule) > 0 {
|
||||
if len(c.NonResourceURLs) > 0 || len(c.Verbs) > 0 || len(c.Resources) > 0 || len(c.ResourceNames) > 0 {
|
||||
return fmt.Errorf("aggregation rule must be specified without nonResourceURLs, verbs, resources or resourceNames")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validate verbs.
|
||||
if len(c.Verbs) == 0 {
|
||||
return fmt.Errorf("at least one verb must be specified")
|
||||
@ -156,26 +171,36 @@ func (c *CreateClusterRoleOptions) Validate() error {
|
||||
}
|
||||
|
||||
func (c *CreateClusterRoleOptions) RunCreateRole() error {
|
||||
clusterRole := &rbacv1.ClusterRole{}
|
||||
clusterRole.Name = c.Name
|
||||
rules, err := generateResourcePolicyRules(c.Mapper, c.Verbs, c.Resources, c.ResourceNames, c.NonResourceURLs)
|
||||
if err != nil {
|
||||
return err
|
||||
clusterRole := &rbacv1.ClusterRole{
|
||||
// this is ok because we know exactly how we want to be serialized
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: rbacv1.SchemeGroupVersion.String(), Kind: "ClusterRole"},
|
||||
}
|
||||
clusterRole.Name = c.Name
|
||||
|
||||
var err error
|
||||
if len(c.AggregationRule) == 0 {
|
||||
rules, err := generateResourcePolicyRules(c.Mapper, c.Verbs, c.Resources, c.ResourceNames, c.NonResourceURLs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clusterRole.Rules = rules
|
||||
} else {
|
||||
clusterRole.AggregationRule = &rbacv1.AggregationRule{
|
||||
ClusterRoleSelectors: []metav1.LabelSelector{
|
||||
{
|
||||
MatchLabels: c.AggregationRule,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
clusterRole.Rules = rules
|
||||
|
||||
// Create ClusterRole.
|
||||
if !c.DryRun {
|
||||
_, err = c.Client.ClusterRoles().Create(clusterRole)
|
||||
clusterRole, err = c.Client.ClusterRoles().Create(clusterRole)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if useShortOutput := c.OutputFormat == "name"; useShortOutput || len(c.OutputFormat) == 0 {
|
||||
cmdutil.PrintSuccess(useShortOutput, c.Out, clusterRole, c.DryRun, "created")
|
||||
return nil
|
||||
}
|
||||
|
||||
return c.PrintObject(clusterRole)
|
||||
return c.PrintObj(clusterRole)
|
||||
}
|
@ -14,26 +14,31 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
func TestCreateClusterRole(t *testing.T) {
|
||||
clusterRoleName := "my-cluster-role"
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.Namespace = "test"
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{}
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
@ -42,12 +47,14 @@ func TestCreateClusterRole(t *testing.T) {
|
||||
resources string
|
||||
nonResourceURL string
|
||||
resourceNames string
|
||||
aggregationRule string
|
||||
expectedClusterRole *rbac.ClusterRole
|
||||
}{
|
||||
"test-duplicate-resources": {
|
||||
verbs: "get,watch,list",
|
||||
resources: "pods,pods",
|
||||
expectedClusterRole: &rbac.ClusterRole{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: clusterRoleName,
|
||||
},
|
||||
@ -65,6 +72,7 @@ func TestCreateClusterRole(t *testing.T) {
|
||||
verbs: "get,watch,list",
|
||||
resources: "pods,deployments.extensions",
|
||||
expectedClusterRole: &rbac.ClusterRole{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: clusterRoleName,
|
||||
},
|
||||
@ -88,6 +96,7 @@ func TestCreateClusterRole(t *testing.T) {
|
||||
verbs: "get",
|
||||
nonResourceURL: "/logs/,/healthz",
|
||||
expectedClusterRole: &rbac.ClusterRole{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: clusterRoleName,
|
||||
},
|
||||
@ -104,6 +113,7 @@ func TestCreateClusterRole(t *testing.T) {
|
||||
nonResourceURL: "/logs/,/healthz",
|
||||
resources: "pods",
|
||||
expectedClusterRole: &rbac.ClusterRole{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: clusterRoleName,
|
||||
},
|
||||
@ -121,16 +131,36 @@ func TestCreateClusterRole(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"test-aggregation-rules": {
|
||||
aggregationRule: "foo1=foo2,foo3=foo4",
|
||||
expectedClusterRole: &rbac.ClusterRole{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: clusterRoleName,
|
||||
},
|
||||
AggregationRule: &rbac.AggregationRule{
|
||||
ClusterRoleSelectors: []metav1.LabelSelector{
|
||||
{
|
||||
MatchLabels: map[string]string{
|
||||
"foo1": "foo2",
|
||||
"foo3": "foo4",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateClusterRole(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateClusterRole(tf, ioStreams)
|
||||
cmd.Flags().Set("dry-run", "true")
|
||||
cmd.Flags().Set("output", "yaml")
|
||||
cmd.Flags().Set("verb", test.verbs)
|
||||
cmd.Flags().Set("resource", test.resources)
|
||||
cmd.Flags().Set("non-resource-url", test.nonResourceURL)
|
||||
cmd.Flags().Set("aggregation-rule", test.aggregationRule)
|
||||
if test.resourceNames != "" {
|
||||
cmd.Flags().Set("resource-name", test.resourceNames)
|
||||
}
|
||||
@ -147,8 +177,8 @@ func TestCreateClusterRole(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestClusterRoleValidate(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.Namespace = "test"
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tests := map[string]struct {
|
||||
clusterRoleOptions *CreateClusterRoleOptions
|
||||
@ -422,12 +452,60 @@ func TestClusterRoleValidate(t *testing.T) {
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
"test-aggregation-rule-with-verb": {
|
||||
clusterRoleOptions: &CreateClusterRoleOptions{
|
||||
CreateRoleOptions: &CreateRoleOptions{
|
||||
Name: "my-clusterrole",
|
||||
Verbs: []string{"get"},
|
||||
},
|
||||
AggregationRule: map[string]string{"foo-key": "foo-vlue"},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
"test-aggregation-rule-with-resource": {
|
||||
clusterRoleOptions: &CreateClusterRoleOptions{
|
||||
CreateRoleOptions: &CreateRoleOptions{
|
||||
Name: "my-clusterrole",
|
||||
Resources: []ResourceOptions{
|
||||
{
|
||||
Resource: "replicasets",
|
||||
SubResource: "scale",
|
||||
},
|
||||
},
|
||||
},
|
||||
AggregationRule: map[string]string{"foo-key": "foo-vlue"},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
"test-aggregation-rule-with-no-resource-url": {
|
||||
clusterRoleOptions: &CreateClusterRoleOptions{
|
||||
CreateRoleOptions: &CreateRoleOptions{
|
||||
Name: "my-clusterrole",
|
||||
},
|
||||
NonResourceURLs: []string{"/logs/"},
|
||||
AggregationRule: map[string]string{"foo-key": "foo-vlue"},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
"test-aggregation-rule": {
|
||||
clusterRoleOptions: &CreateClusterRoleOptions{
|
||||
CreateRoleOptions: &CreateRoleOptions{
|
||||
Name: "my-clusterrole",
|
||||
},
|
||||
AggregationRule: map[string]string{"foo-key": "foo-vlue"},
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
test.clusterRoleOptions.Mapper, _ = tf.Object()
|
||||
err := test.clusterRoleOptions.Validate()
|
||||
var err error
|
||||
test.clusterRoleOptions.Mapper, err = tf.ToRESTMapper()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = test.clusterRoleOptions.Validate()
|
||||
if test.expectErr && err == nil {
|
||||
t.Errorf("%s: expect error happens, but validate passes.", name)
|
||||
}
|
||||
@ -437,3 +515,14 @@ func TestClusterRoleValidate(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func defaultClientConfig() *restclient.Config {
|
||||
return &restclient.Config{
|
||||
APIPath: "/api",
|
||||
ContentConfig: restclient.ContentConfig{
|
||||
NegotiatedSerializer: scheme.Codecs,
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
GroupVersion: &schema.GroupVersion{Version: "v1"},
|
||||
},
|
||||
}
|
||||
}
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -36,8 +35,16 @@ var (
|
||||
kubectl create clusterrolebinding cluster-admin --clusterrole=cluster-admin --user=user1 --user=user2 --group=group1`))
|
||||
)
|
||||
|
||||
type ClusterRoleBindingOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// ClusterRoleBinding is a command to ease creating ClusterRoleBindings.
|
||||
func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &ClusterRoleBindingOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "clusterrolebinding NAME --clusterrole=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -45,13 +52,15 @@ func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.
|
||||
Long: clusterRoleBindingLong,
|
||||
Example: clusterRoleBindingExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateClusterRoleBinding(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ClusterRoleBindingV1GeneratorName)
|
||||
cmd.Flags().String("clusterrole", "", i18n.T("ClusterRole this ClusterRoleBinding should reference"))
|
||||
cmd.MarkFlagCustom("clusterrole", "__kubectl_get_resource_clusterrole")
|
||||
@ -61,12 +70,12 @@ func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateClusterRoleBinding is the implementation of the create clusterrolebinding command.
|
||||
func CreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *ClusterRoleBindingOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ClusterRoleBindingV1GeneratorName:
|
||||
@ -80,10 +89,11 @@ func CreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Co
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateClusterRoleBinding is the implementation of the create clusterrolebinding command.
|
||||
func (o *ClusterRoleBindingOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -32,6 +32,7 @@ import (
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
func TestCreateClusterRoleBinding(t *testing.T) {
|
||||
@ -67,14 +68,15 @@ func TestCreateClusterRoleBinding(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
|
||||
encoder := ns.EncoderForVersion(info.Serializer, groupVersion)
|
||||
decoder := ns.DecoderToVersion(info.Serializer, groupVersion)
|
||||
|
||||
tf.Namespace = "test"
|
||||
tf.Client = &ClusterRoleBindingRESTClient{
|
||||
RESTClient: &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
@ -109,8 +111,8 @@ func TestCreateClusterRoleBinding(t *testing.T) {
|
||||
}
|
||||
|
||||
expectedOutput := "clusterrolebinding.rbac.authorization.k8s.io/" + expectBinding.Name + "\n"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateClusterRoleBinding(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateClusterRoleBinding(tf, ioStreams)
|
||||
cmd.Flags().Set("clusterrole", "fake-clusterrole")
|
||||
cmd.Flags().Set("user", "fake-user")
|
||||
cmd.Flags().Set("group", "fake-group")
|
||||
@ -143,3 +145,9 @@ func (c *ClusterRoleBindingRESTClient) Post() *restclient.Request {
|
||||
}
|
||||
return restclient.NewRequest(c, "POST", &url.URL{Host: "localhost"}, c.VersionedAPIPath, config, serializers, nil, nil, 0)
|
||||
}
|
||||
|
||||
func defaultHeader() http.Header {
|
||||
header := http.Header{}
|
||||
header.Set("Content-Type", runtime.ContentTypeJSON)
|
||||
return header
|
||||
}
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -57,8 +56,16 @@ var (
|
||||
kubectl create configmap my-config --from-env-file=path/to/bar.env`))
|
||||
)
|
||||
|
||||
type ConfigMapOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// ConfigMap is a command to ease creating ConfigMaps.
|
||||
func NewCmdCreateConfigMap(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateConfigMap(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &ConfigMapOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -67,13 +74,15 @@ func NewCmdCreateConfigMap(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
Long: configMapLong,
|
||||
Example: configMapExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateConfigMap(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ConfigMapV1GeneratorName)
|
||||
cmd.Flags().StringSlice("from-file", []string{}, "Key file can be specified using its file path, in which case file basename will be used as configmap key, or optionally with a key and file path, in which case the given key will be used. Specifying a directory will iterate each named file in the directory whose basename is a valid configmap key.")
|
||||
cmd.Flags().StringArray("from-literal", []string{}, "Specify a key and literal value to insert in configmap (i.e. mykey=somevalue)")
|
||||
@ -82,12 +91,12 @@ func NewCmdCreateConfigMap(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateConfigMap is the implementation of the create configmap command.
|
||||
func CreateConfigMap(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *ConfigMapOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ConfigMapV1GeneratorName:
|
||||
@ -101,10 +110,11 @@ func CreateConfigMap(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ar
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateConfigMap is the implementation of the create configmap command.
|
||||
func (o *ConfigMapOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,26 +14,32 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
func TestCreateConfigMap(t *testing.T) {
|
||||
configMap := &v1.ConfigMap{}
|
||||
configMap.Name = "my-configmap"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -49,9 +55,8 @@ func TestCreateConfigMap(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateConfigMap(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateConfigMap(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{configMap.Name})
|
||||
expectedOutput := "configmap/" + configMap.Name + "\n"
|
||||
@ -59,3 +64,7 @@ func TestCreateConfigMap(t *testing.T) {
|
||||
t.Errorf("expected output: %s, but got: %s", expectedOutput, buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
func objBody(codec runtime.Codec, obj runtime.Object) io.ReadCloser {
|
||||
return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, obj))))
|
||||
}
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -36,10 +35,18 @@ var (
|
||||
kubectl create deployment my-dep --image=busybox`))
|
||||
)
|
||||
|
||||
type DeploymentOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateDeployment is a macro command to create a new deployment.
|
||||
// This command is better known to users as `kubectl create deployment`.
|
||||
// Note that this command overlaps significantly with the `kubectl run` command.
|
||||
func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.Command {
|
||||
func NewCmdCreateDeployment(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &DeploymentOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "deployment NAME --image=image [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -48,14 +55,16 @@ func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.
|
||||
Long: deploymentLong,
|
||||
Example: deploymentExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := createDeployment(f, cmdOut, cmdErr, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.DeploymentBasicV1Beta1GeneratorName)
|
||||
cmdutil.AddGeneratorFlags(cmd, "")
|
||||
cmd.Flags().StringSlice("image", []string{}, "Image name to run.")
|
||||
cmd.MarkFlagRequired("image")
|
||||
return cmd
|
||||
@ -71,7 +80,7 @@ func generatorFromName(
|
||||
) (kubectl.StructuredGenerator, bool) {
|
||||
|
||||
switch generatorName {
|
||||
case cmdutil.DeploymentBasicAppsV1Beta1GeneratorName:
|
||||
case cmdutil.DeploymentBasicAppsV1GeneratorName:
|
||||
generator := &kubectl.DeploymentBasicAppsGeneratorV1{
|
||||
BaseDeploymentGenerator: kubectl.BaseDeploymentGenerator{
|
||||
Name: deploymentName,
|
||||
@ -80,6 +89,15 @@ func generatorFromName(
|
||||
}
|
||||
return generator, true
|
||||
|
||||
case cmdutil.DeploymentBasicAppsV1Beta1GeneratorName:
|
||||
generator := &kubectl.DeploymentBasicAppsGeneratorV1Beta1{
|
||||
BaseDeploymentGenerator: kubectl.BaseDeploymentGenerator{
|
||||
Name: deploymentName,
|
||||
Images: imageNames,
|
||||
},
|
||||
}
|
||||
return generator, true
|
||||
|
||||
case cmdutil.DeploymentBasicV1Beta1GeneratorName:
|
||||
generator := &kubectl.DeploymentBasicGeneratorV1{
|
||||
BaseDeploymentGenerator: kubectl.BaseDeploymentGenerator{
|
||||
@ -93,14 +111,8 @@ func generatorFromName(
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// createDeployment
|
||||
// 1. Reads user config values from Cobra.
|
||||
// 2. Sets up the correct Generator object.
|
||||
// 3. Calls RunCreateSubcommand.
|
||||
func createDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer,
|
||||
cmd *cobra.Command, args []string) error {
|
||||
|
||||
deploymentName, err := NameFromCommandArgs(cmd, args)
|
||||
func (o *DeploymentOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -112,23 +124,32 @@ func createDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer,
|
||||
|
||||
generatorName := cmdutil.GetFlagString(cmd, "generator")
|
||||
|
||||
// It is possible we have to modify the user-provided generator name if
|
||||
// the server does not have support for the requested generator.
|
||||
generatorName, err = cmdutil.FallbackGeneratorNameIfNecessary(generatorName, clientset.Discovery(), cmdErr)
|
||||
if err != nil {
|
||||
return err
|
||||
if len(generatorName) == 0 {
|
||||
generatorName = cmdutil.DeploymentBasicAppsV1GeneratorName
|
||||
generatorNameTemp, err := cmdutil.FallbackGeneratorNameIfNecessary(generatorName, clientset.Discovery(), o.CreateSubcommandOptions.ErrOut)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if generatorNameTemp != generatorName {
|
||||
cmdutil.Warning(o.CreateSubcommandOptions.ErrOut, generatorName, generatorNameTemp)
|
||||
} else {
|
||||
generatorName = generatorNameTemp
|
||||
}
|
||||
}
|
||||
|
||||
imageNames := cmdutil.GetFlagStringSlice(cmd, "image")
|
||||
generator, ok := generatorFromName(generatorName, imageNames, deploymentName)
|
||||
generator, ok := generatorFromName(generatorName, imageNames, name)
|
||||
if !ok {
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: deploymentName,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// createDeployment
|
||||
// 1. Reads user config values from Cobra.
|
||||
// 2. Sets up the correct Generator object.
|
||||
// 3. Calls RunCreateSubcommand.
|
||||
func (o *DeploymentOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -30,14 +30,16 @@ import (
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
func Test_generatorFromName(t *testing.T) {
|
||||
const (
|
||||
nonsenseName = "not-a-real-generator-name"
|
||||
basicName = cmdutil.DeploymentBasicV1Beta1GeneratorName
|
||||
basicAppsName = cmdutil.DeploymentBasicAppsV1Beta1GeneratorName
|
||||
deploymentName = "deployment-name"
|
||||
nonsenseName = "not-a-real-generator-name"
|
||||
basicName = cmdutil.DeploymentBasicV1Beta1GeneratorName
|
||||
basicAppsV1Beta1Name = cmdutil.DeploymentBasicAppsV1Beta1GeneratorName
|
||||
basicAppsV1Name = cmdutil.DeploymentBasicAppsV1GeneratorName
|
||||
deploymentName = "deployment-name"
|
||||
)
|
||||
imageNames := []string{"image-1", "image-2"}
|
||||
|
||||
@ -58,7 +60,20 @@ func Test_generatorFromName(t *testing.T) {
|
||||
assert.Equal(t, expectedGenerator, generator)
|
||||
}
|
||||
|
||||
generator, ok = generatorFromName(basicAppsName, imageNames, deploymentName)
|
||||
generator, ok = generatorFromName(basicAppsV1Beta1Name, imageNames, deploymentName)
|
||||
assert.True(t, ok)
|
||||
|
||||
{
|
||||
expectedGenerator := &kubectl.DeploymentBasicAppsGeneratorV1Beta1{
|
||||
BaseDeploymentGenerator: kubectl.BaseDeploymentGenerator{
|
||||
Name: deploymentName,
|
||||
Images: imageNames,
|
||||
},
|
||||
}
|
||||
assert.Equal(t, expectedGenerator, generator)
|
||||
}
|
||||
|
||||
generator, ok = generatorFromName(basicAppsV1Name, imageNames, deploymentName)
|
||||
assert.True(t, ok)
|
||||
|
||||
{
|
||||
@ -74,28 +89,29 @@ func Test_generatorFromName(t *testing.T) {
|
||||
|
||||
func TestCreateDeployment(t *testing.T) {
|
||||
depName := "jonny-dep"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.Codecs
|
||||
fakeDiscovery := "{\"kind\":\"APIResourceList\",\"apiVersion\":\"v1\",\"groupVersion\":\"apps/v1\",\"resources\":[{\"name\":\"deployments\",\"singularName\":\"\",\"namespaced\":true,\"kind\":\"Deployment\",\"verbs\":[\"create\",\"delete\",\"deletecollection\",\"get\",\"list\",\"patch\",\"update\",\"watch\"],\"shortNames\":[\"deploy\"],\"categories\":[\"all\"]}]}"
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: ioutil.NopCloser(bytes.NewBuffer([]byte("{}"))),
|
||||
Body: ioutil.NopCloser(bytes.NewBuffer([]byte(fakeDiscovery))),
|
||||
}, nil
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = &restclient.Config{}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdCreateDeployment(tf, buf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateDeployment(tf, ioStreams)
|
||||
cmd.Flags().Set("dry-run", "true")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Flags().Set("image", "hollywood/jonny.depp:v2")
|
||||
cmd.Run(cmd, []string{depName})
|
||||
expectedOutput := "deployment.extensions/" + depName + "\n"
|
||||
expectedOutput := "deployment.apps/" + depName + "\n"
|
||||
if buf.String() != expectedOutput {
|
||||
t.Errorf("expected output: %s, but got: %s", expectedOutput, buf.String())
|
||||
}
|
||||
@ -103,25 +119,38 @@ func TestCreateDeployment(t *testing.T) {
|
||||
|
||||
func TestCreateDeploymentNoImage(t *testing.T) {
|
||||
depName := "jonny-dep"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.Codecs
|
||||
fakeDiscovery := "{\"kind\":\"APIResourceList\",\"apiVersion\":\"v1\",\"groupVersion\":\"apps/v1\",\"resources\":[{\"name\":\"deployments\",\"singularName\":\"\",\"namespaced\":true,\"kind\":\"Deployment\",\"verbs\":[\"create\",\"delete\",\"deletecollection\",\"get\",\"list\",\"patch\",\"update\",\"watch\"],\"shortNames\":[\"deploy\"],\"categories\":[\"all\"]}]}"
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: ioutil.NopCloser(&bytes.Buffer{}),
|
||||
Body: ioutil.NopCloser(bytes.NewBuffer([]byte(fakeDiscovery))),
|
||||
}, nil
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = &restclient.Config{}
|
||||
tf.Namespace = "test"
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateDeployment(tf, buf, buf)
|
||||
cmd.Flags().Set("dry-run", "true")
|
||||
ioStreams := genericclioptions.NewTestIOStreamsDiscard()
|
||||
cmd := NewCmdCreateDeployment(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
err := createDeployment(tf, buf, buf, cmd, []string{depName})
|
||||
options := &DeploymentOpts{
|
||||
CreateSubcommandOptions: &CreateSubcommandOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
DryRun: true,
|
||||
IOStreams: ioStreams,
|
||||
},
|
||||
}
|
||||
|
||||
err := options.Complete(tf, cmd, []string{depName})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
err = options.Run()
|
||||
assert.Error(t, err, "at least one image must be specified")
|
||||
}
|
186
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create/create_job.go
generated
vendored
Normal file
186
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create/create_job.go
generated
vendored
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
Copyright 2018 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 create
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
batchv1beta1 "k8s.io/api/batch/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
clientbatchv1 "k8s.io/client-go/kubernetes/typed/batch/v1"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
var (
|
||||
jobLong = templates.LongDesc(i18n.T(`
|
||||
Create a job with the specified name.`))
|
||||
|
||||
jobExample = templates.Examples(i18n.T(`
|
||||
# Create a job from a CronJob named "a-cronjob"
|
||||
kubectl create job test-job --from=cronjob/a-cronjob`))
|
||||
)
|
||||
|
||||
type CreateJobOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
|
||||
PrintObj func(obj runtime.Object) error
|
||||
|
||||
Name string
|
||||
From string
|
||||
|
||||
Namespace string
|
||||
OutputFormat string
|
||||
Client clientbatchv1.BatchV1Interface
|
||||
DryRun bool
|
||||
Builder *resource.Builder
|
||||
Cmd *cobra.Command
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewCreateJobOptions(ioStreams genericclioptions.IOStreams) *CreateJobOptions {
|
||||
return &CreateJobOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCmdCreateJob is a command to ease creating Jobs from CronJobs.
|
||||
func NewCmdCreateJob(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewCreateJobOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "job NAME [--from=CRONJOB]",
|
||||
Short: jobLong,
|
||||
Long: jobLong,
|
||||
Example: jobExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.RunCreateJob())
|
||||
},
|
||||
}
|
||||
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmd.Flags().StringVar(&o.From, "from", o.From, "The name of the resource to create a Job from (only cronjob is supported).")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *CreateJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) (err error) {
|
||||
if len(args) == 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "NAME is required")
|
||||
}
|
||||
o.Name = args[0]
|
||||
|
||||
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientset, err := f.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.Client = clientset.BatchV1()
|
||||
o.Builder = f.NewBuilder()
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
o.Cmd = cmd
|
||||
o.OutputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.PrintObj = func(obj runtime.Object) error {
|
||||
return printer.PrintObj(obj, o.Out)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *CreateJobOptions) RunCreateJob() error {
|
||||
infos, err := o.Builder.
|
||||
Unstructured().
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
ResourceTypeOrNameArgs(false, o.From).
|
||||
Flatten().
|
||||
Latest().
|
||||
Do().
|
||||
Infos()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(infos) != 1 {
|
||||
return fmt.Errorf("from must be an existing cronjob")
|
||||
}
|
||||
|
||||
uncastVersionedObj, err := scheme.Scheme.ConvertToVersion(infos[0].Object, batchv1beta1.SchemeGroupVersion)
|
||||
if err != nil {
|
||||
return fmt.Errorf("from must be an existing cronjob: %v", err)
|
||||
}
|
||||
cronJob, ok := uncastVersionedObj.(*batchv1beta1.CronJob)
|
||||
if !ok {
|
||||
return fmt.Errorf("from must be an existing cronjob")
|
||||
}
|
||||
|
||||
return o.createJob(cronJob)
|
||||
}
|
||||
|
||||
func (o *CreateJobOptions) createJob(cronJob *batchv1beta1.CronJob) error {
|
||||
annotations := make(map[string]string)
|
||||
annotations["cronjob.kubernetes.io/instantiate"] = "manual"
|
||||
for k, v := range cronJob.Spec.JobTemplate.Annotations {
|
||||
annotations[k] = v
|
||||
}
|
||||
job := &batchv1.Job{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: o.Name,
|
||||
Namespace: o.Namespace,
|
||||
Annotations: annotations,
|
||||
Labels: cronJob.Spec.JobTemplate.Labels,
|
||||
},
|
||||
Spec: cronJob.Spec.JobTemplate.Spec,
|
||||
}
|
||||
|
||||
if !o.DryRun {
|
||||
var err error
|
||||
job, err = o.Client.Jobs(o.Namespace).Create(job)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create job: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return o.PrintObj(job)
|
||||
}
|
@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
@ -27,7 +26,9 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
fake "k8s.io/client-go/kubernetes/fake"
|
||||
clienttesting "k8s.io/client-go/testing"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
func TestCreateJobFromCronJob(t *testing.T) {
|
||||
@ -82,13 +83,26 @@ func TestCreateJobFromCronJob(t *testing.T) {
|
||||
return true, expectJob, nil
|
||||
})
|
||||
f := cmdtesting.NewTestFactory()
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
defer f.Cleanup()
|
||||
|
||||
printFlags := genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme)
|
||||
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmdOptions := &CreateJobOptions{
|
||||
Name: testJobName,
|
||||
Namespace: testNamespaceName,
|
||||
Client: clientset.BatchV1(),
|
||||
Out: buf,
|
||||
Cmd: NewCmdCreateJob(f, buf),
|
||||
PrintFlags: printFlags,
|
||||
Name: testJobName,
|
||||
Namespace: testNamespaceName,
|
||||
Client: clientset.BatchV1(),
|
||||
Cmd: NewCmdCreateJob(f, ioStreams),
|
||||
PrintObj: func(obj runtime.Object) error {
|
||||
p, err := printFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.PrintObj(obj, buf)
|
||||
},
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
|
||||
err := cmdOptions.createJob(cronJob)
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -36,8 +35,16 @@ var (
|
||||
kubectl create namespace my-namespace`))
|
||||
)
|
||||
|
||||
type NamespaceOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateNamespace is a macro command to create a new namespace
|
||||
func NewCmdCreateNamespace(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateNamespace(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &NamespaceOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "namespace NAME [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -46,24 +53,26 @@ func NewCmdCreateNamespace(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
Long: namespaceLong,
|
||||
Example: namespaceExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateNamespace(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.NamespaceV1GeneratorName)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateNamespace implements the behavior to run the create namespace command
|
||||
func CreateNamespace(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *NamespaceOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.NamespaceV1GeneratorName:
|
||||
@ -71,10 +80,11 @@ func CreateNamespace(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ar
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateNamespace implements the behavior to run the create namespace command
|
||||
func (o *NamespaceOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@ -26,6 +25,7 @@ import (
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
@ -33,7 +33,9 @@ func TestCreateNamespace(t *testing.T) {
|
||||
namespaceObject := &v1.Namespace{}
|
||||
namespaceObject.Name = "my-namespace"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -49,8 +51,8 @@ func TestCreateNamespace(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateNamespace(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateNamespace(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{namespaceObject.Name})
|
||||
expectedOutput := "namespace/" + namespaceObject.Name + "\n"
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -41,8 +40,16 @@ var (
|
||||
kubectl create pdb my-pdb --selector=app=nginx --min-available=50%`))
|
||||
)
|
||||
|
||||
type PodDisruptionBudgetOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreatePodDisruptionBudget is a macro command to create a new pod disruption budget.
|
||||
func NewCmdCreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreatePodDisruptionBudget(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &PodDisruptionBudgetOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "poddisruptionbudget NAME --selector=SELECTOR --min-available=N [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -51,14 +58,15 @@ func NewCmdCreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer) *cobra
|
||||
Long: pdbLong,
|
||||
Example: pdbExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreatePodDisruptionBudget(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.PodDisruptionBudgetV2GeneratorName)
|
||||
|
||||
cmd.Flags().String("min-available", "", i18n.T("The minimum number or percentage of available pods this budget requires."))
|
||||
@ -67,12 +75,12 @@ func NewCmdCreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer) *cobra
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreatePodDisruptionBudget implements the behavior to run the create pdb command.
|
||||
func CreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *PodDisruptionBudgetOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.PodDisruptionBudgetV1GeneratorName:
|
||||
@ -91,10 +99,11 @@ func CreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreatePodDisruptionBudget implements the behavior to run the create pdb command.
|
||||
func (o *PodDisruptionBudgetOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -27,11 +27,14 @@ import (
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
func TestCreatePdb(t *testing.T) {
|
||||
pdbName := "my-pdb"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -45,15 +48,36 @@ func TestCreatePdb(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = &restclient.Config{}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdCreatePodDisruptionBudget(tf, buf)
|
||||
outputFormat := "name"
|
||||
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreatePodDisruptionBudget(tf, ioStreams)
|
||||
cmd.Flags().Set("min-available", "1")
|
||||
cmd.Flags().Set("selector", "app=rails")
|
||||
cmd.Flags().Set("dry-run", "true")
|
||||
cmd.Flags().Set("output", "name")
|
||||
CreatePodDisruptionBudget(tf, buf, cmd, []string{pdbName})
|
||||
cmd.Flags().Set("output", outputFormat)
|
||||
|
||||
printFlags := genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme)
|
||||
printFlags.OutputFormat = &outputFormat
|
||||
|
||||
options := &PodDisruptionBudgetOpts{
|
||||
CreateSubcommandOptions: &CreateSubcommandOptions{
|
||||
PrintFlags: printFlags,
|
||||
Name: pdbName,
|
||||
IOStreams: ioStreams,
|
||||
},
|
||||
}
|
||||
err := options.Complete(tf, cmd, []string{pdbName})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
err = options.Run()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
expectedOutput := "poddisruptionbudget.policy/" + pdbName + "\n"
|
||||
if buf.String() != expectedOutput {
|
||||
t.Errorf("expected output: %s, but got: %s", expectedOutput, buf.String())
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -39,8 +38,16 @@ var (
|
||||
kubectl create priorityclass default-priority --value=1000 --global-default=true --description="default priority"`))
|
||||
)
|
||||
|
||||
type PriorityClassOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreatePriorityClass is a macro command to create a new priorityClass.
|
||||
func NewCmdCreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreatePriorityClass(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &PriorityClassOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "priorityclass NAME --value=VALUE --global-default=BOOL [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -49,13 +56,15 @@ func NewCmdCreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comma
|
||||
Long: pcLong,
|
||||
Example: pcExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(CreatePriorityClass(f, cmdOut, cmd, args))
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.PriorityClassV1Alpha1GeneratorName)
|
||||
|
||||
cmd.Flags().Int32("value", 0, i18n.T("the value of this priority class."))
|
||||
@ -64,12 +73,12 @@ func NewCmdCreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comma
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreatePriorityClass implements the behavior to run the create priorityClass command.
|
||||
func CreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *PriorityClassOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.PriorityClassV1Alpha1GeneratorName:
|
||||
@ -82,10 +91,11 @@ func CreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreatePriorityClass implements the behavior to run the create priorityClass command.
|
||||
func (o *PriorityClassOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -27,15 +27,18 @@ import (
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
func TestCreatePriorityClass(t *testing.T) {
|
||||
pcName := "my-pc"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "scheduling.k8s.io", Version: "v1alpha1"},
|
||||
GroupVersion: schema.GroupVersion{Group: "scheduling.k8s.io", Version: "v1beta1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
return &http.Response{
|
||||
@ -45,15 +48,37 @@ func TestCreatePriorityClass(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = &restclient.Config{}
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdCreatePriorityClass(tf, buf)
|
||||
outputFormat := "name"
|
||||
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreatePriorityClass(tf, ioStreams)
|
||||
cmd.Flags().Set("value", "1000")
|
||||
cmd.Flags().Set("global-default", "true")
|
||||
cmd.Flags().Set("description", "my priority")
|
||||
cmd.Flags().Set("dry-run", "true")
|
||||
cmd.Flags().Set("output", "name")
|
||||
CreatePriorityClass(tf, buf, cmd, []string{pcName})
|
||||
cmd.Flags().Set("output", outputFormat)
|
||||
|
||||
printFlags := genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme)
|
||||
printFlags.OutputFormat = &outputFormat
|
||||
|
||||
options := &PriorityClassOpts{
|
||||
CreateSubcommandOptions: &CreateSubcommandOptions{
|
||||
PrintFlags: printFlags,
|
||||
Name: pcName,
|
||||
IOStreams: ioStreams,
|
||||
},
|
||||
}
|
||||
err := options.Complete(tf, cmd, []string{pcName})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
err = options.Run()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
expectedOutput := "priorityclass.scheduling.k8s.io/" + pcName + "\n"
|
||||
if buf.String() != expectedOutput {
|
||||
t.Errorf("expected output: %s, but got: %s", expectedOutput, buf.String())
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -39,8 +38,16 @@ var (
|
||||
kubectl create quota best-effort --hard=pods=100 --scopes=BestEffort`))
|
||||
)
|
||||
|
||||
type QuotaOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateQuota is a macro command to create a new quota
|
||||
func NewCmdCreateQuota(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateQuota(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &QuotaOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "quota NAME [--hard=key1=value1,key2=value2] [--scopes=Scope1,Scope2] [--dry-run=bool]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -49,26 +56,27 @@ func NewCmdCreateQuota(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
Long: quotaLong,
|
||||
Example: quotaExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateQuota(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ResourceQuotaV1GeneratorName)
|
||||
cmd.Flags().String("hard", "", i18n.T("A comma-delimited set of resource=quantity pairs that define a hard limit."))
|
||||
cmd.Flags().String("scopes", "", i18n.T("A comma-delimited set of quota scopes that must all match each object tracked by the quota."))
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateQuota implements the behavior to run the create quota command
|
||||
func CreateQuota(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *QuotaOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ResourceQuotaV1GeneratorName:
|
||||
@ -80,10 +88,11 @@ func CreateQuota(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args [
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateQuota implements the behavior to run the create quota command
|
||||
func (o *QuotaOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,42 +14,19 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
func TestCreateQuota(t *testing.T) {
|
||||
resourceQuotaObject := &v1.ResourceQuota{}
|
||||
resourceQuotaObject.Name = "my-quota"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Version: "v1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == "/namespaces/test/resourcequotas" && m == "POST":
|
||||
return &http.Response{StatusCode: 201, Header: defaultHeader(), Body: objBody(codec, resourceQuotaObject)}, nil
|
||||
default:
|
||||
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
return nil, nil
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
|
||||
tests := map[string]struct {
|
||||
flags []string
|
||||
@ -73,14 +50,19 @@ func TestCreateQuota(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for name, test := range tests {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateQuota(tf, buf)
|
||||
cmd.Flags().Parse(test.flags)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{resourceQuotaObject.Name})
|
||||
t.Run(name, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
if buf.String() != test.expectedOutput {
|
||||
t.Errorf("%s: expected output: %s, but got: %s", name, test.expectedOutput, buf.String())
|
||||
}
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateQuota(tf, ioStreams)
|
||||
cmd.Flags().Parse(test.flags)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{resourceQuotaObject.Name})
|
||||
|
||||
if buf.String() != test.expectedOutput {
|
||||
t.Errorf("%s: expected output: %s, but got: %s", name, test.expectedOutput, buf.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -14,23 +14,25 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
clientgorbacv1 "k8s.io/client-go/kubernetes/typed/rbac/v1"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -43,7 +45,7 @@ var (
|
||||
kubectl create role pod-reader --verb=get --verb=list --verb=watch --resource=pods
|
||||
|
||||
# Create a Role named "pod-reader" with ResourceName specified
|
||||
kubectl create role pod-reader --verb=get,list,watch --resource=pods --resource-name=readablepod --resource-name=anotherpod
|
||||
kubectl create role pod-reader --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod
|
||||
|
||||
# Create a Role named "foo" with API Group specified
|
||||
kubectl create role foo --verb=get,list,watch --resource=rs.extensions
|
||||
@ -100,6 +102,8 @@ type ResourceOptions struct {
|
||||
}
|
||||
|
||||
type CreateRoleOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
|
||||
Name string
|
||||
Verbs []string
|
||||
Resources []ResourceOptions
|
||||
@ -110,15 +114,23 @@ type CreateRoleOptions struct {
|
||||
Namespace string
|
||||
Client clientgorbacv1.RbacV1Interface
|
||||
Mapper meta.RESTMapper
|
||||
Out io.Writer
|
||||
PrintObject func(obj runtime.Object) error
|
||||
PrintObj func(obj runtime.Object) error
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewCreateRoleOptions(ioStreams genericclioptions.IOStreams) *CreateRoleOptions {
|
||||
return &CreateRoleOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
// Role is a command to ease creating Roles.
|
||||
func NewCmdCreateRole(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
c := &CreateRoleOptions{
|
||||
Out: cmdOut,
|
||||
}
|
||||
func NewCmdCreateRole(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewCreateRoleOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "role NAME --verb=verb --resource=resource.group/subresource [--resource-name=resourcename] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -126,32 +138,34 @@ func NewCmdCreateRole(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
Long: roleLong,
|
||||
Example: roleExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(c.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(c.Validate())
|
||||
cmdutil.CheckErr(c.RunCreateRole())
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.RunCreateRole())
|
||||
},
|
||||
}
|
||||
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmd.Flags().StringSliceVar(&c.Verbs, "verb", []string{}, "Verb that applies to the resources contained in the rule")
|
||||
cmd.Flags().StringSliceVar(&o.Verbs, "verb", o.Verbs, "Verb that applies to the resources contained in the rule")
|
||||
cmd.Flags().StringSlice("resource", []string{}, "Resource that the rule applies to")
|
||||
cmd.Flags().StringArrayVar(&c.ResourceNames, "resource-name", []string{}, "Resource in the white list that the rule applies to, repeat this flag for multiple items")
|
||||
cmd.Flags().StringArrayVar(&o.ResourceNames, "resource-name", o.ResourceNames, "Resource in the white list that the rule applies to, repeat this flag for multiple items")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
func (o *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Name = name
|
||||
o.Name = name
|
||||
|
||||
// Remove duplicate verbs.
|
||||
verbs := []string{}
|
||||
for _, v := range c.Verbs {
|
||||
for _, v := range o.Verbs {
|
||||
// VerbAll respresents all kinds of verbs.
|
||||
if v == "*" {
|
||||
verbs = []string{"*"}
|
||||
@ -161,7 +175,7 @@ func (c *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
|
||||
verbs = append(verbs, v)
|
||||
}
|
||||
}
|
||||
c.Verbs = verbs
|
||||
o.Verbs = verbs
|
||||
|
||||
// Support resource.group pattern. If no API Group specified, use "" as core API Group.
|
||||
// e.g. --resource=pods,deployments.extensions
|
||||
@ -180,79 +194,89 @@ func (c *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
|
||||
}
|
||||
resource.Resource = parts[0]
|
||||
|
||||
c.Resources = append(c.Resources, *resource)
|
||||
o.Resources = append(o.Resources, *resource)
|
||||
}
|
||||
|
||||
// Remove duplicate resource names.
|
||||
resourceNames := []string{}
|
||||
for _, n := range c.ResourceNames {
|
||||
for _, n := range o.ResourceNames {
|
||||
if !arrayContains(resourceNames, n) {
|
||||
resourceNames = append(resourceNames, n)
|
||||
}
|
||||
}
|
||||
c.ResourceNames = resourceNames
|
||||
o.ResourceNames = resourceNames
|
||||
|
||||
// Complete other options for Run.
|
||||
c.Mapper, _ = f.Object()
|
||||
|
||||
c.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
c.OutputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
|
||||
c.Namespace, _, err = f.DefaultNamespace()
|
||||
o.Mapper, err = f.ToRESTMapper()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.PrintObject = func(obj runtime.Object) error {
|
||||
return cmdutil.PrintObject(cmd, obj, c.Out)
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
o.OutputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.PrintObj = func(obj runtime.Object) error {
|
||||
return printer.PrintObj(obj, o.Out)
|
||||
}
|
||||
|
||||
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientset, err := f.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Client = clientset.RbacV1()
|
||||
o.Client = clientset.RbacV1()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CreateRoleOptions) Validate() error {
|
||||
if c.Name == "" {
|
||||
func (o *CreateRoleOptions) Validate() error {
|
||||
if o.Name == "" {
|
||||
return fmt.Errorf("name must be specified")
|
||||
}
|
||||
|
||||
// validate verbs.
|
||||
if len(c.Verbs) == 0 {
|
||||
if len(o.Verbs) == 0 {
|
||||
return fmt.Errorf("at least one verb must be specified")
|
||||
}
|
||||
|
||||
for _, v := range c.Verbs {
|
||||
for _, v := range o.Verbs {
|
||||
if !arrayContains(validResourceVerbs, v) {
|
||||
return fmt.Errorf("invalid verb: '%s'", v)
|
||||
}
|
||||
}
|
||||
|
||||
// validate resources.
|
||||
if len(c.Resources) == 0 {
|
||||
if len(o.Resources) == 0 {
|
||||
return fmt.Errorf("at least one resource must be specified")
|
||||
}
|
||||
|
||||
return c.validateResource()
|
||||
return o.validateResource()
|
||||
}
|
||||
|
||||
func (c *CreateRoleOptions) validateResource() error {
|
||||
for _, r := range c.Resources {
|
||||
func (o *CreateRoleOptions) validateResource() error {
|
||||
for _, r := range o.Resources {
|
||||
if len(r.Resource) == 0 {
|
||||
return fmt.Errorf("resource must be specified if apiGroup/subresource specified")
|
||||
}
|
||||
|
||||
resource := schema.GroupVersionResource{Resource: r.Resource, Group: r.Group}
|
||||
groupVersionResource, err := c.Mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group})
|
||||
groupVersionResource, err := o.Mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group})
|
||||
if err == nil {
|
||||
resource = groupVersionResource
|
||||
}
|
||||
|
||||
for _, v := range c.Verbs {
|
||||
for _, v := range o.Verbs {
|
||||
if groupResources, ok := specialVerbs[v]; ok {
|
||||
match := false
|
||||
for _, extra := range groupResources {
|
||||
@ -275,29 +299,27 @@ func (c *CreateRoleOptions) validateResource() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CreateRoleOptions) RunCreateRole() error {
|
||||
role := &rbacv1.Role{}
|
||||
role.Name = c.Name
|
||||
rules, err := generateResourcePolicyRules(c.Mapper, c.Verbs, c.Resources, c.ResourceNames, []string{})
|
||||
func (o *CreateRoleOptions) RunCreateRole() error {
|
||||
role := &rbacv1.Role{
|
||||
// this is ok because we know exactly how we want to be serialized
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: rbacv1.SchemeGroupVersion.String(), Kind: "Role"},
|
||||
}
|
||||
role.Name = o.Name
|
||||
rules, err := generateResourcePolicyRules(o.Mapper, o.Verbs, o.Resources, o.ResourceNames, []string{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
role.Rules = rules
|
||||
|
||||
// Create role.
|
||||
if !c.DryRun {
|
||||
_, err = c.Client.Roles(c.Namespace).Create(role)
|
||||
if !o.DryRun {
|
||||
role, err = o.Client.Roles(o.Namespace).Create(role)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if useShortOutput := c.OutputFormat == "name"; useShortOutput || len(c.OutputFormat) == 0 {
|
||||
cmdutil.PrintSuccess(useShortOutput, c.Out, role, c.DryRun, "created")
|
||||
return nil
|
||||
}
|
||||
|
||||
return c.PrintObject(role)
|
||||
return o.PrintObj(role)
|
||||
}
|
||||
|
||||
func arrayContains(s []string, e string) bool {
|
@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@ -29,13 +28,15 @@ import (
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
func TestCreateRole(t *testing.T) {
|
||||
roleName := "my-role"
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.Namespace = "test"
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{}
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
@ -49,6 +50,7 @@ func TestCreateRole(t *testing.T) {
|
||||
verbs: "get,watch,list",
|
||||
resources: "pods,pods",
|
||||
expectedRole: &rbac.Role{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "Role"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: roleName,
|
||||
},
|
||||
@ -66,6 +68,7 @@ func TestCreateRole(t *testing.T) {
|
||||
verbs: "get,watch,list",
|
||||
resources: "replicasets/scale",
|
||||
expectedRole: &rbac.Role{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "Role"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: roleName,
|
||||
},
|
||||
@ -83,6 +86,7 @@ func TestCreateRole(t *testing.T) {
|
||||
verbs: "get,watch,list",
|
||||
resources: "replicasets.extensions/scale",
|
||||
expectedRole: &rbac.Role{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "Role"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: roleName,
|
||||
},
|
||||
@ -100,6 +104,7 @@ func TestCreateRole(t *testing.T) {
|
||||
verbs: "get,watch,list",
|
||||
resources: "pods,deployments.extensions",
|
||||
expectedRole: &rbac.Role{
|
||||
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "Role"},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: roleName,
|
||||
},
|
||||
@ -123,8 +128,8 @@ func TestCreateRole(t *testing.T) {
|
||||
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateRole(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateRole(tf, ioStreams)
|
||||
cmd.Flags().Set("dry-run", "true")
|
||||
cmd.Flags().Set("output", "yaml")
|
||||
cmd.Flags().Set("verb", test.verbs)
|
||||
@ -146,8 +151,8 @@ func TestCreateRole(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.Namespace = "test"
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tests := map[string]struct {
|
||||
roleOptions *CreateRoleOptions
|
||||
@ -331,8 +336,12 @@ func TestValidate(t *testing.T) {
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
test.roleOptions.Mapper, _ = tf.Object()
|
||||
err := test.roleOptions.Validate()
|
||||
var err error
|
||||
test.roleOptions.Mapper, err = tf.ToRESTMapper()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = test.roleOptions.Validate()
|
||||
if test.expectErr && err == nil {
|
||||
t.Errorf("%s: expect error happens but validate passes.", name)
|
||||
}
|
||||
@ -345,13 +354,13 @@ func TestValidate(t *testing.T) {
|
||||
func TestComplete(t *testing.T) {
|
||||
roleName := "my-role"
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.Namespace = "test"
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{}
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateRole(tf, buf)
|
||||
cmd := NewCmdCreateRole(tf, genericclioptions.NewTestIOStreamsDiscard())
|
||||
cmd.Flags().Set("resource", "pods,deployments.extensions")
|
||||
|
||||
tests := map[string]struct {
|
||||
@ -361,14 +370,17 @@ func TestComplete(t *testing.T) {
|
||||
expectErr bool
|
||||
}{
|
||||
"test-missing-name": {
|
||||
params: []string{},
|
||||
roleOptions: &CreateRoleOptions{},
|
||||
expectErr: true,
|
||||
params: []string{},
|
||||
roleOptions: &CreateRoleOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
"test-duplicate-verbs": {
|
||||
params: []string{roleName},
|
||||
roleOptions: &CreateRoleOptions{
|
||||
Name: roleName,
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
Name: roleName,
|
||||
Verbs: []string{
|
||||
"get",
|
||||
"watch",
|
||||
@ -400,7 +412,8 @@ func TestComplete(t *testing.T) {
|
||||
"test-verball": {
|
||||
params: []string{roleName},
|
||||
roleOptions: &CreateRoleOptions{
|
||||
Name: roleName,
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
Name: roleName,
|
||||
Verbs: []string{
|
||||
"get",
|
||||
"watch",
|
||||
@ -428,6 +441,7 @@ func TestComplete(t *testing.T) {
|
||||
"test-duplicate-resourcenames": {
|
||||
params: []string{roleName},
|
||||
roleOptions: &CreateRoleOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
Name: roleName,
|
||||
Verbs: []string{"*"},
|
||||
ResourceNames: []string{"foo", "foo"},
|
||||
@ -452,6 +466,7 @@ func TestComplete(t *testing.T) {
|
||||
"test-valid-complete-case": {
|
||||
params: []string{roleName},
|
||||
roleOptions: &CreateRoleOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(legacyscheme.Scheme),
|
||||
Name: roleName,
|
||||
Verbs: []string{"*"},
|
||||
ResourceNames: []string{"foo"},
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -36,8 +35,16 @@ var (
|
||||
kubectl create rolebinding admin --clusterrole=admin --user=user1 --user=user2 --group=group1`))
|
||||
)
|
||||
|
||||
type RoleBindingOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// RoleBinding is a command to ease creating RoleBindings.
|
||||
func NewCmdCreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateRoleBinding(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &RoleBindingOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -45,13 +52,15 @@ func NewCmdCreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command
|
||||
Long: roleBindingLong,
|
||||
Example: roleBindingExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateRoleBinding(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.RoleBindingV1GeneratorName)
|
||||
cmd.Flags().String("clusterrole", "", i18n.T("ClusterRole this RoleBinding should reference"))
|
||||
cmd.Flags().String("role", "", i18n.T("Role this RoleBinding should reference"))
|
||||
@ -61,11 +70,12 @@ func NewCmdCreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command
|
||||
return cmd
|
||||
}
|
||||
|
||||
func CreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *RoleBindingOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.RoleBindingV1GeneratorName:
|
||||
@ -80,10 +90,10 @@ func CreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command,
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
func (o *RoleBindingOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -32,6 +32,7 @@ import (
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
var groupVersion = schema.GroupVersion{Group: "rbac.authorization.k8s.io", Version: "v1"}
|
||||
@ -69,14 +70,15 @@ func TestCreateRoleBinding(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
|
||||
encoder := ns.EncoderForVersion(info.Serializer, groupVersion)
|
||||
decoder := ns.DecoderToVersion(info.Serializer, groupVersion)
|
||||
|
||||
tf.Namespace = "test"
|
||||
tf.Client = &RoleBindingRESTClient{
|
||||
RESTClient: &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
@ -110,8 +112,7 @@ func TestCreateRoleBinding(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateRoleBinding(tf, buf)
|
||||
cmd := NewCmdCreateRoleBinding(tf, genericclioptions.NewTestIOStreamsDiscard())
|
||||
cmd.Flags().Set("role", "fake-role")
|
||||
cmd.Flags().Set("user", "fake-user")
|
||||
cmd.Flags().Set("group", "fake-group")
|
@ -14,30 +14,29 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
// NewCmdCreateSecret groups subcommands to create various types of secrets
|
||||
func NewCmdCreateSecret(f cmdutil.Factory, cmdOut, errOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateSecret(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "secret",
|
||||
Short: i18n.T("Create a secret using specified subcommand"),
|
||||
Long: "Create a secret using specified subcommand.",
|
||||
Run: cmdutil.DefaultSubCommandRun(errOut),
|
||||
Run: cmdutil.DefaultSubCommandRun(ioStreams.ErrOut),
|
||||
}
|
||||
cmd.AddCommand(NewCmdCreateSecretDockerRegistry(f, cmdOut))
|
||||
cmd.AddCommand(NewCmdCreateSecretTLS(f, cmdOut))
|
||||
cmd.AddCommand(NewCmdCreateSecretGeneric(f, cmdOut))
|
||||
cmd.AddCommand(NewCmdCreateSecretDockerRegistry(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateSecretTLS(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateSecretGeneric(f, ioStreams))
|
||||
|
||||
return cmd
|
||||
}
|
||||
@ -73,8 +72,16 @@ var (
|
||||
kubectl create secret generic my-secret --from-env-file=path/to/bar.env`))
|
||||
)
|
||||
|
||||
type SecretGenericOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateSecretGeneric is a command to create generic secrets from files, directories, or literal values
|
||||
func NewCmdCreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateSecretGeneric(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &SecretGenericOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "generic NAME [--type=string] [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -82,13 +89,15 @@ func NewCmdCreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comma
|
||||
Long: secretLong,
|
||||
Example: secretExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateSecretGeneric(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.SecretV1GeneratorName)
|
||||
cmd.Flags().StringSlice("from-file", []string{}, "Key files can be specified using their file path, in which case a default name will be given to them, or optionally with a name and file path, in which case the given name will be used. Specifying a directory will iterate each named file in the directory that is a valid secret key.")
|
||||
cmd.Flags().StringArray("from-literal", []string{}, "Specify a key and literal value to insert in secret (i.e. mykey=somevalue)")
|
||||
@ -98,12 +107,12 @@ func NewCmdCreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comma
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateSecretGeneric is the implementation of the create secret generic command
|
||||
func CreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *SecretGenericOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.SecretV1GeneratorName:
|
||||
@ -118,12 +127,13 @@ func CreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateSecretGeneric is the implementation of the create secret generic command
|
||||
func (o *SecretGenericOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
||||
|
||||
var (
|
||||
@ -135,7 +145,7 @@ var (
|
||||
When using the Docker command line to push images, you can authenticate to a given registry by running:
|
||||
'$ docker login DOCKER_REGISTRY_SERVER --username=DOCKER_USER --password=DOCKER_PASSWORD --email=DOCKER_EMAIL'.
|
||||
|
||||
That produces a ~/.dockercfg file that is used by subsequent 'docker push' and 'docker pull' commands to
|
||||
That produces a ~/.dockercfg file that is used by subsequent 'docker push' and 'docker pull' commands to
|
||||
authenticate to the registry. The email address is optional.
|
||||
|
||||
When creating applications, you may have a Docker registry that requires authentication. In order for the
|
||||
@ -147,8 +157,16 @@ var (
|
||||
kubectl create secret docker-registry my-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL`))
|
||||
)
|
||||
|
||||
type SecretDockerRegistryOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateSecretDockerRegistry is a macro command for creating secrets to work with Docker registries
|
||||
func NewCmdCreateSecretDockerRegistry(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateSecretDockerRegistry(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &SecretDockerRegistryOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "docker-registry NAME --docker-username=user --docker-password=password --docker-email=email [--docker-server=string] [--from-literal=key1=value1] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -156,13 +174,15 @@ func NewCmdCreateSecretDockerRegistry(f cmdutil.Factory, cmdOut io.Writer) *cobr
|
||||
Long: secretForDockerRegistryLong,
|
||||
Example: secretForDockerRegistryExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateSecretDockerRegistry(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.SecretForDockerRegistryV1GeneratorName)
|
||||
cmd.Flags().String("docker-username", "", i18n.T("Username for Docker registry authentication"))
|
||||
cmd.MarkFlagRequired("docker-username")
|
||||
@ -171,43 +191,49 @@ func NewCmdCreateSecretDockerRegistry(f cmdutil.Factory, cmdOut io.Writer) *cobr
|
||||
cmd.Flags().String("docker-email", "", i18n.T("Email for Docker registry"))
|
||||
cmd.Flags().String("docker-server", "https://index.docker.io/v1/", i18n.T("Server location for Docker registry"))
|
||||
cmd.Flags().Bool("append-hash", false, "Append a hash of the secret to its name.")
|
||||
cmd.Flags().StringSlice("from-file", []string{}, "Key files can be specified using their file path, in which case a default name will be given to them, or optionally with a name and file path, in which case the given name will be used. Specifying a directory will iterate each named file in the directory that is a valid secret key.")
|
||||
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateSecretDockerRegistry is the implementation of the create secret docker-registry command
|
||||
func CreateSecretDockerRegistry(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *SecretDockerRegistryOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
requiredFlags := []string{"docker-username", "docker-password", "docker-email", "docker-server"}
|
||||
for _, requiredFlag := range requiredFlags {
|
||||
if value := cmdutil.GetFlagString(cmd, requiredFlag); len(value) == 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "flag %s is required", requiredFlag)
|
||||
|
||||
fromFileFlag := cmdutil.GetFlagStringSlice(cmd, "from-file")
|
||||
if len(fromFileFlag) == 0 {
|
||||
requiredFlags := []string{"docker-username", "docker-password", "docker-server"}
|
||||
for _, requiredFlag := range requiredFlags {
|
||||
if value := cmdutil.GetFlagString(cmd, requiredFlag); len(value) == 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "flag %s is required", requiredFlag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.SecretForDockerRegistryV1GeneratorName:
|
||||
generator = &kubectl.SecretForDockerRegistryGeneratorV1{
|
||||
Name: name,
|
||||
Username: cmdutil.GetFlagString(cmd, "docker-username"),
|
||||
Email: cmdutil.GetFlagString(cmd, "docker-email"),
|
||||
Password: cmdutil.GetFlagString(cmd, "docker-password"),
|
||||
Server: cmdutil.GetFlagString(cmd, "docker-server"),
|
||||
AppendHash: cmdutil.GetFlagBool(cmd, "append-hash"),
|
||||
Name: name,
|
||||
Username: cmdutil.GetFlagString(cmd, "docker-username"),
|
||||
Email: cmdutil.GetFlagString(cmd, "docker-email"),
|
||||
Password: cmdutil.GetFlagString(cmd, "docker-password"),
|
||||
Server: cmdutil.GetFlagString(cmd, "docker-server"),
|
||||
AppendHash: cmdutil.GetFlagBool(cmd, "append-hash"),
|
||||
FileSources: cmdutil.GetFlagStringSlice(cmd, "from-file"),
|
||||
}
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateSecretDockerRegistry is the implementation of the create secret docker-registry command
|
||||
func (o *SecretDockerRegistryOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
||||
|
||||
var (
|
||||
@ -222,8 +248,16 @@ var (
|
||||
kubectl create secret tls tls-secret --cert=path/to/tls.cert --key=path/to/tls.key`))
|
||||
)
|
||||
|
||||
type SecretTLSOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateSecretTLS is a macro command for creating secrets to work with Docker registries
|
||||
func NewCmdCreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateSecretTLS(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &SecretTLSOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "tls NAME --cert=path/to/cert/file --key=path/to/key/file [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -231,13 +265,15 @@ func NewCmdCreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
Long: secretForTLSLong,
|
||||
Example: secretForTLSExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateSecretTLS(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.SecretForTLSV1GeneratorName)
|
||||
cmd.Flags().String("cert", "", i18n.T("Path to PEM encoded public key certificate."))
|
||||
cmd.Flags().String("key", "", i18n.T("Path to private key associated with given certificate."))
|
||||
@ -245,12 +281,12 @@ func NewCmdCreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateSecretTLS is the implementation of the create secret tls command
|
||||
func CreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *SecretTLSOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
requiredFlags := []string{"cert", "key"}
|
||||
for _, requiredFlag := range requiredFlags {
|
||||
if value := cmdutil.GetFlagString(cmd, requiredFlag); len(value) == 0 {
|
||||
@ -269,10 +305,11 @@ func CreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ar
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateSecretTLS is the implementation of the create secret tls command
|
||||
func (o *SecretTLSOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@ -26,6 +25,7 @@ import (
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
@ -37,8 +37,10 @@ func TestCreateSecretGeneric(t *testing.T) {
|
||||
},
|
||||
}
|
||||
secretObject.Name = "my-secret"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -54,9 +56,8 @@ func TestCreateSecretGeneric(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateSecretGeneric(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateSecretGeneric(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Flags().Set("from-literal", "password=includes,comma")
|
||||
cmd.Flags().Set("from-literal", "username=test_user")
|
||||
@ -70,8 +71,8 @@ func TestCreateSecretGeneric(t *testing.T) {
|
||||
func TestCreateSecretDockerRegistry(t *testing.T) {
|
||||
secretObject := &v1.Secret{}
|
||||
secretObject.Name = "my-secret"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -87,9 +88,8 @@ func TestCreateSecretDockerRegistry(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateSecretDockerRegistry(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateSecretDockerRegistry(tf, ioStreams)
|
||||
cmd.Flags().Set("docker-username", "test-user")
|
||||
cmd.Flags().Set("docker-password", "test-pass")
|
||||
cmd.Flags().Set("docker-email", "test-email")
|
@ -14,33 +14,32 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
// NewCmdCreateService is a macro command to create a new service
|
||||
func NewCmdCreateService(f cmdutil.Factory, cmdOut, errOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateService(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "service",
|
||||
Aliases: []string{"svc"},
|
||||
Short: i18n.T("Create a service using specified subcommand."),
|
||||
Long: "Create a service using specified subcommand.",
|
||||
Run: cmdutil.DefaultSubCommandRun(errOut),
|
||||
Run: cmdutil.DefaultSubCommandRun(ioStreams.ErrOut),
|
||||
}
|
||||
cmd.AddCommand(NewCmdCreateServiceClusterIP(f, cmdOut))
|
||||
cmd.AddCommand(NewCmdCreateServiceNodePort(f, cmdOut))
|
||||
cmd.AddCommand(NewCmdCreateServiceLoadBalancer(f, cmdOut))
|
||||
cmd.AddCommand(NewCmdCreateServiceExternalName(f, cmdOut))
|
||||
cmd.AddCommand(NewCmdCreateServiceClusterIP(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateServiceNodePort(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateServiceLoadBalancer(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdCreateServiceExternalName(f, ioStreams))
|
||||
|
||||
return cmd
|
||||
}
|
||||
@ -61,8 +60,16 @@ func addPortFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().StringSlice("tcp", []string{}, "Port pairs can be specified as '<port>:<targetPort>'.")
|
||||
}
|
||||
|
||||
type ServiceClusterIPOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateServiceClusterIP is a command to create a ClusterIP service
|
||||
func NewCmdCreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateServiceClusterIP(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &ServiceClusterIPOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "clusterip NAME [--tcp=<port>:<targetPort>] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -70,13 +77,15 @@ func NewCmdCreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer) *cobra.Co
|
||||
Long: serviceClusterIPLong,
|
||||
Example: serviceClusterIPExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateServiceClusterIP(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceClusterIPGeneratorV1Name)
|
||||
addPortFlags(cmd)
|
||||
cmd.Flags().String("clusterip", "", i18n.T("Assign your own ClusterIP or set to 'None' for a 'headless' service (no loadbalancing)."))
|
||||
@ -87,12 +96,12 @@ func errUnsupportedGenerator(cmd *cobra.Command, generatorName string) error {
|
||||
return cmdutil.UsageErrorf(cmd, "Generator %s not supported. ", generatorName)
|
||||
}
|
||||
|
||||
// CreateServiceClusterIP is the implementation of the create service clusterip command
|
||||
func CreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *ServiceClusterIPOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ServiceClusterIPGeneratorV1Name:
|
||||
@ -105,12 +114,13 @@ func CreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comm
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateServiceClusterIP is the implementation of the create service clusterip command
|
||||
func (o *ServiceClusterIPOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
||||
|
||||
var (
|
||||
@ -122,8 +132,16 @@ var (
|
||||
kubectl create service nodeport my-ns --tcp=5678:8080`))
|
||||
)
|
||||
|
||||
type ServiceNodePortOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateServiceNodePort is a macro command for creating a NodePort service
|
||||
func NewCmdCreateServiceNodePort(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateServiceNodePort(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &ServiceNodePortOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "nodeport NAME [--tcp=port:targetPort] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -131,25 +149,27 @@ func NewCmdCreateServiceNodePort(f cmdutil.Factory, cmdOut io.Writer) *cobra.Com
|
||||
Long: serviceNodePortLong,
|
||||
Example: serviceNodePortExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateServiceNodePort(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceNodePortGeneratorV1Name)
|
||||
cmd.Flags().Int("node-port", 0, "Port used to expose the service on each node in a cluster.")
|
||||
addPortFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateServiceNodePort is the implementation of the create service nodeport command
|
||||
func CreateServiceNodePort(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *ServiceNodePortOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ServiceNodePortGeneratorV1Name:
|
||||
@ -163,12 +183,13 @@ func CreateServiceNodePort(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comma
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateServiceNodePort is the implementation of the create service nodeport command
|
||||
func (o *ServiceNodePortOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
||||
|
||||
var (
|
||||
@ -180,8 +201,16 @@ var (
|
||||
kubectl create service loadbalancer my-lbs --tcp=5678:8080`))
|
||||
)
|
||||
|
||||
type ServiceLoadBalancerOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateServiceLoadBalancer is a macro command for creating a LoadBalancer service
|
||||
func NewCmdCreateServiceLoadBalancer(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateServiceLoadBalancer(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &ServiceLoadBalancerOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "loadbalancer NAME [--tcp=port:targetPort] [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -189,24 +218,26 @@ func NewCmdCreateServiceLoadBalancer(f cmdutil.Factory, cmdOut io.Writer) *cobra
|
||||
Long: serviceLoadBalancerLong,
|
||||
Example: serviceLoadBalancerExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateServiceLoadBalancer(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceLoadBalancerGeneratorV1Name)
|
||||
addPortFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateServiceLoadBalancer is the implementation of the create service loadbalancer command
|
||||
func CreateServiceLoadBalancer(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *ServiceLoadBalancerOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ServiceLoadBalancerGeneratorV1Name:
|
||||
@ -219,12 +250,13 @@ func CreateServiceLoadBalancer(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateServiceLoadBalancer is the implementation of the create service loadbalancer command
|
||||
func (o *ServiceLoadBalancerOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
||||
|
||||
var (
|
||||
@ -236,12 +268,20 @@ var (
|
||||
that exist off platform, on other clusters, or locally.`))
|
||||
|
||||
serviceExternalNameExample = templates.Examples(i18n.T(`
|
||||
# Create a new ExternalName service named my-ns
|
||||
# Create a new ExternalName service named my-ns
|
||||
kubectl create service externalname my-ns --external-name bar.com`))
|
||||
)
|
||||
|
||||
type ServiceExternalNameOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateServiceExternalName is a macro command for creating an ExternalName service
|
||||
func NewCmdCreateServiceExternalName(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateServiceExternalName(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &ServiceExternalNameOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "externalname NAME --external-name external.name [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -249,13 +289,15 @@ func NewCmdCreateServiceExternalName(f cmdutil.Factory, cmdOut io.Writer) *cobra
|
||||
Long: serviceExternalNameLong,
|
||||
Example: serviceExternalNameExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateExternalNameService(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceExternalNameGeneratorV1Name)
|
||||
addPortFlags(cmd)
|
||||
cmd.Flags().String("external-name", "", i18n.T("External name of service"))
|
||||
@ -263,12 +305,12 @@ func NewCmdCreateServiceExternalName(f cmdutil.Factory, cmdOut io.Writer) *cobra
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateExternalNameService is the implementation of the create service externalname command
|
||||
func CreateExternalNameService(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *ServiceExternalNameOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ServiceExternalNameGeneratorV1Name:
|
||||
@ -281,10 +323,11 @@ func CreateExternalNameService(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateExternalNameService is the implementation of the create service externalname command
|
||||
func (o *ServiceExternalNameOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@ -26,14 +25,17 @@ import (
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
func TestCreateService(t *testing.T) {
|
||||
service := &v1.Service{}
|
||||
service.Name = "my-service"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
negSer := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -49,9 +51,8 @@ func TestCreateService(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateServiceClusterIP(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateServiceClusterIP(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Flags().Set("tcp", "8080:8000")
|
||||
cmd.Run(cmd, []string{service.Name})
|
||||
@ -64,8 +65,10 @@ func TestCreateService(t *testing.T) {
|
||||
func TestCreateServiceNodePort(t *testing.T) {
|
||||
service := &v1.Service{}
|
||||
service.Name = "my-node-port-service"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
negSer := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -81,9 +84,8 @@ func TestCreateServiceNodePort(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateServiceNodePort(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateServiceNodePort(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Flags().Set("tcp", "30000:8000")
|
||||
cmd.Run(cmd, []string{service.Name})
|
||||
@ -96,8 +98,10 @@ func TestCreateServiceNodePort(t *testing.T) {
|
||||
func TestCreateServiceExternalName(t *testing.T) {
|
||||
service := &v1.Service{}
|
||||
service.Name = "my-external-name-service"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
negSer := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -113,9 +117,8 @@ func TestCreateServiceExternalName(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateServiceExternalName(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateServiceExternalName(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Flags().Set("external-name", "name")
|
||||
cmd.Run(cmd, []string{service.Name})
|
@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -36,8 +35,16 @@ var (
|
||||
kubectl create serviceaccount my-service-account`))
|
||||
)
|
||||
|
||||
type ServiceAccountOpts struct {
|
||||
CreateSubcommandOptions *CreateSubcommandOptions
|
||||
}
|
||||
|
||||
// NewCmdCreateServiceAccount is a macro command to create a new service account
|
||||
func NewCmdCreateServiceAccount(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
func NewCmdCreateServiceAccount(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &ServiceAccountOpts{
|
||||
CreateSubcommandOptions: NewCreateSubcommandOptions(ioStreams),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "serviceaccount NAME [--dry-run]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -46,24 +53,25 @@ func NewCmdCreateServiceAccount(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comm
|
||||
Long: serviceAccountLong,
|
||||
Example: serviceAccountExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateServiceAccount(f, cmdOut, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceAccountV1GeneratorName)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CreateServiceAccount implements the behavior to run the create service account command
|
||||
func CreateServiceAccount(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *ServiceAccountOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
name, err := NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.ServiceAccountV1GeneratorName:
|
||||
@ -71,10 +79,11 @@ func CreateServiceAccount(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comman
|
||||
default:
|
||||
return errUnsupportedGenerator(cmd, generatorName)
|
||||
}
|
||||
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
|
||||
Name: name,
|
||||
StructuredGenerator: generator,
|
||||
DryRun: cmdutil.GetDryRunFlag(cmd),
|
||||
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
|
||||
})
|
||||
|
||||
return o.CreateSubcommandOptions.Complete(f, cmd, args, generator)
|
||||
}
|
||||
|
||||
// CreateServiceAccount implements the behavior to run the create service account command
|
||||
func (o *ServiceAccountOpts) Run() error {
|
||||
return o.CreateSubcommandOptions.Run()
|
||||
}
|
@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@ -26,14 +25,17 @@ import (
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
func TestCreateServiceAccount(t *testing.T) {
|
||||
serviceAccountObject := &v1.ServiceAccount{}
|
||||
serviceAccountObject.Name = "my-service-account"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
@ -49,9 +51,8 @@ func TestCreateServiceAccount(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateServiceAccount(tf, buf)
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreateServiceAccount(tf, ioStreams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{serviceAccountObject.Name})
|
||||
expectedOutput := "serviceaccount/" + serviceAccountObject.Name + "\n"
|
@ -14,27 +14,32 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package create
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
func TestExtraArgsFail(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
f := cmdtesting.NewTestFactory()
|
||||
c := NewCmdCreate(f, buf, errBuf)
|
||||
defer f.Cleanup()
|
||||
|
||||
c := NewCmdCreate(f, genericclioptions.NewTestIOStreamsDiscard())
|
||||
options := CreateOptions{}
|
||||
if options.ValidateArgs(c, []string{"rc"}) == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
@ -46,8 +51,10 @@ func TestCreateObject(t *testing.T) {
|
||||
_, _, rc := testData()
|
||||
rc.Items[0].Name = "redis-master-controller"
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Version: "v1"},
|
||||
@ -62,12 +69,10 @@ func TestCreateObject(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdCreate(tf, buf, errBuf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy/redis-master-controller.yaml")
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreate(tf, ioStreams)
|
||||
cmd.Flags().Set("filename", "../../../../test/e2e/testing-manifests/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{})
|
||||
|
||||
@ -81,8 +86,10 @@ func TestCreateMultipleObject(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, svc, rc := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Version: "v1"},
|
||||
@ -99,13 +106,11 @@ func TestCreateMultipleObject(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdCreate(tf, buf, errBuf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/frontend-service.yaml")
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreate(tf, ioStreams)
|
||||
cmd.Flags().Set("filename", "../../../../test/e2e/testing-manifests/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("filename", "../../../../test/e2e/testing-manifests/guestbook/frontend-service.yaml")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{})
|
||||
|
||||
@ -120,8 +125,10 @@ func TestCreateDirectory(t *testing.T) {
|
||||
_, _, rc := testData()
|
||||
rc.Items[0].Name = "name"
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Version: "v1"},
|
||||
@ -136,12 +143,10 @@ func TestCreateDirectory(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdCreate(tf, buf, errBuf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy")
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdCreate(tf, ioStreams)
|
||||
cmd.Flags().Set("filename", "../../../../test/e2e/testing-manifests/guestbook/legacy")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{})
|
||||
|
||||
@ -149,3 +154,57 @@ func TestCreateDirectory(t *testing.T) {
|
||||
t.Errorf("unexpected output: %s", buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
var unstructuredSerializer = resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer
|
||||
|
||||
func initTestErrorHandler(t *testing.T) {
|
||||
cmdutil.BehaviorOnFatal(func(str string, code int) {
|
||||
t.Errorf("Error running command (exit code %d): %s", code, str)
|
||||
})
|
||||
}
|
||||
|
||||
func testData() (*api.PodList, *api.ServiceList, *api.ReplicationControllerList) {
|
||||
pods := &api.PodList{
|
||||
ListMeta: metav1.ListMeta{
|
||||
ResourceVersion: "15",
|
||||
},
|
||||
Items: []api.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "10"},
|
||||
Spec: apitesting.DeepEqualSafePodSpec(),
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "bar", Namespace: "test", ResourceVersion: "11"},
|
||||
Spec: apitesting.DeepEqualSafePodSpec(),
|
||||
},
|
||||
},
|
||||
}
|
||||
svc := &api.ServiceList{
|
||||
ListMeta: metav1.ListMeta{
|
||||
ResourceVersion: "16",
|
||||
},
|
||||
Items: []api.Service{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
|
||||
Spec: api.ServiceSpec{
|
||||
SessionAffinity: "None",
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
rc := &api.ReplicationControllerList{
|
||||
ListMeta: metav1.ListMeta{
|
||||
ResourceVersion: "17",
|
||||
},
|
||||
Items: []api.ReplicationController{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "rc1", Namespace: "test", ResourceVersion: "18"},
|
||||
Spec: api.ReplicationControllerSpec{
|
||||
Replicas: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return pods, svc, rc
|
||||
}
|
146
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create_job.go
generated
vendored
146
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/create_job.go
generated
vendored
@ -1,146 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
batchv1beta1 "k8s.io/api/batch/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientbatchv1 "k8s.io/client-go/kubernetes/typed/batch/v1"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
var (
|
||||
jobLong = templates.LongDesc(i18n.T(`
|
||||
Create a job with the specified name.`))
|
||||
|
||||
jobExample = templates.Examples(i18n.T(`
|
||||
# Create a job from a CronJob named "a-cronjob"
|
||||
kubectl create job --from=cronjob/a-cronjob`))
|
||||
)
|
||||
|
||||
type CreateJobOptions struct {
|
||||
Name string
|
||||
From string
|
||||
|
||||
Namespace string
|
||||
Client clientbatchv1.BatchV1Interface
|
||||
Out io.Writer
|
||||
DryRun bool
|
||||
Builder *resource.Builder
|
||||
Cmd *cobra.Command
|
||||
}
|
||||
|
||||
// NewCmdCreateJob is a command to ease creating Jobs from CronJobs.
|
||||
func NewCmdCreateJob(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
|
||||
c := &CreateJobOptions{
|
||||
Out: cmdOut,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "job NAME [--from-cronjob=CRONJOB]",
|
||||
Short: jobLong,
|
||||
Long: jobLong,
|
||||
Example: jobExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(c.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(c.RunCreateJob())
|
||||
},
|
||||
}
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmd.Flags().String("from", "", "The name of the resource to create a Job from (only cronjob is supported).")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c *CreateJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) (err error) {
|
||||
if len(args) == 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "NAME is required")
|
||||
}
|
||||
c.Name = args[0]
|
||||
|
||||
c.From = cmdutil.GetFlagString(cmd, "from")
|
||||
c.Namespace, _, err = f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientset, err := f.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Client = clientset.BatchV1()
|
||||
c.Builder = f.NewBuilder()
|
||||
c.Cmd = cmd
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CreateJobOptions) RunCreateJob() error {
|
||||
infos, err := c.Builder.
|
||||
Unstructured().
|
||||
NamespaceParam(c.Namespace).DefaultNamespace().
|
||||
ResourceTypeOrNameArgs(false, c.From).
|
||||
Flatten().
|
||||
Latest().
|
||||
Do().
|
||||
Infos()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(infos) != 1 {
|
||||
return fmt.Errorf("from must be an existing cronjob")
|
||||
}
|
||||
cronJob, ok := infos[0].AsVersioned().(*batchv1beta1.CronJob)
|
||||
if !ok {
|
||||
return fmt.Errorf("from must be an existing cronjob")
|
||||
}
|
||||
|
||||
return c.createJob(cronJob)
|
||||
}
|
||||
|
||||
func (c *CreateJobOptions) createJob(cronJob *batchv1beta1.CronJob) error {
|
||||
annotations := make(map[string]string)
|
||||
annotations["cronjob.kubernetes.io/instantiate"] = "manual"
|
||||
for k, v := range cronJob.Spec.JobTemplate.Annotations {
|
||||
annotations[k] = v
|
||||
}
|
||||
jobToCreate := &batchv1.Job{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: c.Name,
|
||||
Namespace: c.Namespace,
|
||||
Annotations: annotations,
|
||||
Labels: cronJob.Spec.JobTemplate.Labels,
|
||||
},
|
||||
Spec: cronJob.Spec.JobTemplate.Spec,
|
||||
}
|
||||
|
||||
job, err := c.Client.Jobs(c.Namespace).Create(jobToCreate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create job: %v", err)
|
||||
}
|
||||
return cmdutil.PrintObject(c.Cmd, job, c.Out)
|
||||
}
|
357
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/delete.go
generated
vendored
357
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/delete.go
generated
vendored
@ -18,20 +18,28 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
kubectlwait "k8s.io/kubernetes/pkg/kubectl/cmd/wait"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -90,7 +98,8 @@ var (
|
||||
type DeleteOptions struct {
|
||||
resource.FilenameOptions
|
||||
|
||||
Selector string
|
||||
LabelSelector string
|
||||
FieldSelector string
|
||||
DeleteAll bool
|
||||
IgnoreNotFound bool
|
||||
Cascade bool
|
||||
@ -101,20 +110,17 @@ type DeleteOptions struct {
|
||||
GracePeriod int
|
||||
Timeout time.Duration
|
||||
|
||||
Include3rdParty bool
|
||||
Output string
|
||||
Output string
|
||||
|
||||
Mapper meta.RESTMapper
|
||||
Result *resource.Result
|
||||
DynamicClient dynamic.Interface
|
||||
Mapper meta.RESTMapper
|
||||
Result *resource.Result
|
||||
|
||||
f cmdutil.Factory
|
||||
Out io.Writer
|
||||
ErrOut io.Writer
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
options := &DeleteOptions{Include3rdParty: true}
|
||||
validArgs := cmdutil.ValidArgList(f)
|
||||
func NewCmdDelete(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
deleteFlags := NewDeleteCommandFlags("containing the resource to delete.")
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "delete ([-f FILENAME] | TYPE [(NAME | -l label | --all)])",
|
||||
@ -123,50 +129,52 @@ func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
Long: delete_long,
|
||||
Example: delete_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
|
||||
if err := options.Complete(f, out, errOut, args, cmd); err != nil {
|
||||
cmdutil.CheckErr(err)
|
||||
}
|
||||
if err := options.Validate(cmd); err != nil {
|
||||
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, err.Error()))
|
||||
}
|
||||
if err := options.RunDelete(); err != nil {
|
||||
cmdutil.CheckErr(err)
|
||||
}
|
||||
o := deleteFlags.ToOptions(nil, streams)
|
||||
cmdutil.CheckErr(o.Complete(f, args, cmd))
|
||||
cmdutil.CheckErr(o.Validate(cmd))
|
||||
cmdutil.CheckErr(o.RunDelete())
|
||||
},
|
||||
SuggestFor: []string{"rm"},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
}
|
||||
usage := "containing the resource to delete."
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on, not including uninitialized ones.")
|
||||
cmd.Flags().BoolVar(&options.DeleteAll, "all", options.DeleteAll, "Delete all resources, including uninitialized ones, in the namespace of the specified resource types.")
|
||||
cmd.Flags().BoolVar(&options.IgnoreNotFound, "ignore-not-found", false, "Treat \"resource not found\" as a successful delete. Defaults to \"true\" when --all is specified.")
|
||||
cmd.Flags().BoolVar(&options.Cascade, "cascade", true, "If true, cascade the deletion of the resources managed by this resource (e.g. Pods created by a ReplicationController). Default true.")
|
||||
cmd.Flags().IntVar(&options.GracePeriod, "grace-period", -1, "Period of time in seconds given to the resource to terminate gracefully. Ignored if negative.")
|
||||
cmd.Flags().BoolVar(&options.DeleteNow, "now", false, "If true, resources are signaled for immediate shutdown (same as --grace-period=1).")
|
||||
cmd.Flags().BoolVar(&options.ForceDeletion, "force", false, "Immediate deletion of some resources may result in inconsistency or data loss and requires confirmation.")
|
||||
cmd.Flags().DurationVar(&options.Timeout, "timeout", 0, "The length of time to wait before giving up on a delete, zero means determine a timeout from the size of the object")
|
||||
cmdutil.AddOutputVarFlagsForMutation(cmd, &options.Output)
|
||||
cmdutil.AddInclude3rdPartyVarFlags(cmd, &options.Include3rdParty)
|
||||
|
||||
deleteFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args []string, cmd *cobra.Command) error {
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
func (o *DeleteOptions) Complete(f cmdutil.Factory, args []string, cmd *cobra.Command) error {
|
||||
cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if o.DeleteAll || len(o.LabelSelector) > 0 || len(o.FieldSelector) > 0 {
|
||||
if f := cmd.Flags().Lookup("ignore-not-found"); f != nil && !f.Changed {
|
||||
// If the user didn't explicitly set the option, default to ignoring NotFound errors when used with --all, -l, or --field-selector
|
||||
o.IgnoreNotFound = true
|
||||
}
|
||||
}
|
||||
if o.DeleteNow {
|
||||
if o.GracePeriod != -1 {
|
||||
return fmt.Errorf("--now and --grace-period cannot be specified together")
|
||||
}
|
||||
o.GracePeriod = 1
|
||||
}
|
||||
if o.GracePeriod == 0 && !o.ForceDeletion {
|
||||
// To preserve backwards compatibility, but prevent accidental data loss, we convert --grace-period=0
|
||||
// into --grace-period=1. Users may provide --force to bypass this conversion.
|
||||
o.GracePeriod = 1
|
||||
}
|
||||
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
r := f.NewBuilder().
|
||||
Unstructured().
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
LabelSelectorParam(o.Selector).
|
||||
LabelSelectorParam(o.LabelSelector).
|
||||
FieldSelectorParam(o.FieldSelector).
|
||||
IncludeUninitialized(includeUninitialized).
|
||||
SelectAllParam(o.DeleteAll).
|
||||
ResourceTypeOrNameArgs(false, args...).RequireObject(false).
|
||||
@ -177,151 +185,185 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args
|
||||
return err
|
||||
}
|
||||
o.Result = r
|
||||
o.Mapper = r.Mapper().RESTMapper
|
||||
|
||||
o.f = f
|
||||
// Set up writer
|
||||
o.Out = out
|
||||
o.ErrOut = errOut
|
||||
o.Mapper, err = f.ToRESTMapper()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.DynamicClient, err = f.DynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *DeleteOptions) Validate(cmd *cobra.Command) error {
|
||||
if o.DeleteAll && len(o.Selector) > 0 {
|
||||
if o.Output != "" && o.Output != "name" {
|
||||
return cmdutil.UsageErrorf(cmd, "Unexpected -o output mode: %v. We only support '-o name'.", o.Output)
|
||||
}
|
||||
|
||||
if o.DeleteAll && len(o.LabelSelector) > 0 {
|
||||
return fmt.Errorf("cannot set --all and --selector at the same time")
|
||||
}
|
||||
if o.DeleteAll {
|
||||
f := cmd.Flags().Lookup("ignore-not-found")
|
||||
// The flag should never be missing
|
||||
if f == nil {
|
||||
return fmt.Errorf("missing --ignore-not-found flag")
|
||||
}
|
||||
// If the user didn't explicitly set the option, default to ignoring NotFound errors when used with --all
|
||||
if !f.Changed {
|
||||
o.IgnoreNotFound = true
|
||||
}
|
||||
if o.DeleteAll && len(o.FieldSelector) > 0 {
|
||||
return fmt.Errorf("cannot set --all and --field-selector at the same time")
|
||||
}
|
||||
if o.DeleteNow {
|
||||
if o.GracePeriod != -1 {
|
||||
return fmt.Errorf("--now and --grace-period cannot be specified together")
|
||||
}
|
||||
o.GracePeriod = 1
|
||||
|
||||
if o.GracePeriod == 0 && !o.ForceDeletion && !o.WaitForDeletion {
|
||||
// With the explicit --wait flag we need extra validation for backward compatibility
|
||||
return fmt.Errorf("--grace-period=0 must have either --force specified, or --wait to be set to true")
|
||||
}
|
||||
if o.GracePeriod == 0 {
|
||||
if o.ForceDeletion {
|
||||
fmt.Fprintf(o.ErrOut, "warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.\n")
|
||||
} else {
|
||||
// To preserve backwards compatibility, but prevent accidental data loss, we convert --grace-period=0
|
||||
// into --grace-period=1 and wait until the object is successfully deleted. Users may provide --force
|
||||
// to bypass this wait.
|
||||
o.WaitForDeletion = true
|
||||
o.GracePeriod = 1
|
||||
}
|
||||
|
||||
switch {
|
||||
case o.GracePeriod == 0 && o.ForceDeletion:
|
||||
fmt.Fprintf(o.ErrOut, "warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.\n")
|
||||
case o.ForceDeletion:
|
||||
fmt.Fprintf(o.ErrOut, "warning: --force is ignored because --grace-period is not 0.\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *DeleteOptions) RunDelete() error {
|
||||
shortOutput := o.Output == "name"
|
||||
// By default use a reaper to delete all related resources.
|
||||
if o.Cascade {
|
||||
return ReapResult(o.Result, o.f, o.Out, true, o.IgnoreNotFound, o.Timeout, o.GracePeriod, o.WaitForDeletion, shortOutput, false)
|
||||
}
|
||||
return DeleteResult(o.Result, o.Out, o.IgnoreNotFound, o.GracePeriod, shortOutput)
|
||||
return o.DeleteResult(o.Result)
|
||||
}
|
||||
|
||||
func ReapResult(r *resource.Result, f cmdutil.Factory, out io.Writer, isDefaultDelete, ignoreNotFound bool, timeout time.Duration, gracePeriod int, waitForDeletion, shortOutput bool, quiet bool) error {
|
||||
func (o *DeleteOptions) DeleteResult(r *resource.Result) error {
|
||||
found := 0
|
||||
if ignoreNotFound {
|
||||
r = r.IgnoreErrors(errors.IsNotFound)
|
||||
}
|
||||
err := r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
found++
|
||||
reaper, err := f.Reaper(info.Mapping)
|
||||
if err != nil {
|
||||
// If there is no reaper for this resources and the user didn't explicitly ask for stop.
|
||||
if kubectl.IsNoSuchReaperError(err) && isDefaultDelete {
|
||||
// No client side reaper found. Let the server do cascading deletion.
|
||||
return cascadingDeleteResource(info, out, shortOutput)
|
||||
}
|
||||
return cmdutil.AddSourceToErr("reaping", info.Source, err)
|
||||
}
|
||||
var options *metav1.DeleteOptions
|
||||
if gracePeriod >= 0 {
|
||||
options = metav1.NewDeleteOptions(int64(gracePeriod))
|
||||
}
|
||||
if err := reaper.Stop(info.Namespace, info.Name, timeout, options); err != nil {
|
||||
return cmdutil.AddSourceToErr("stopping", info.Source, err)
|
||||
}
|
||||
if waitForDeletion {
|
||||
if err := waitForObjectDeletion(info, timeout); err != nil {
|
||||
return cmdutil.AddSourceToErr("stopping", info.Source, err)
|
||||
}
|
||||
}
|
||||
if !quiet {
|
||||
printDeletion(info, out, shortOutput)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if found == 0 {
|
||||
fmt.Fprintf(out, "No resources found\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteResult(r *resource.Result, out io.Writer, ignoreNotFound bool, gracePeriod int, shortOutput bool) error {
|
||||
found := 0
|
||||
if ignoreNotFound {
|
||||
if o.IgnoreNotFound {
|
||||
r = r.IgnoreErrors(errors.IsNotFound)
|
||||
}
|
||||
deletedInfos := []*resource.Info{}
|
||||
err := r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
deletedInfos = append(deletedInfos, info)
|
||||
found++
|
||||
|
||||
// if we're here, it means that cascade=false (not the default), so we should orphan as requested
|
||||
orphan := true
|
||||
options := &metav1.DeleteOptions{}
|
||||
if gracePeriod >= 0 {
|
||||
options = metav1.NewDeleteOptions(int64(gracePeriod))
|
||||
if o.GracePeriod >= 0 {
|
||||
options = metav1.NewDeleteOptions(int64(o.GracePeriod))
|
||||
}
|
||||
options.OrphanDependents = &orphan
|
||||
return deleteResource(info, out, shortOutput, options)
|
||||
policy := metav1.DeletePropagationBackground
|
||||
if !o.Cascade {
|
||||
policy = metav1.DeletePropagationOrphan
|
||||
}
|
||||
options.PropagationPolicy = &policy
|
||||
|
||||
return o.deleteResource(info, options)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if found == 0 {
|
||||
fmt.Fprintf(out, "No resources found\n")
|
||||
fmt.Fprintf(o.Out, "No resources found\n")
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
if !o.WaitForDeletion {
|
||||
return nil
|
||||
}
|
||||
// if we don't have a dynamic client, we don't want to wait. Eventually when delete is cleaned up, this will likely
|
||||
// drop out.
|
||||
if o.DynamicClient == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
effectiveTimeout := o.Timeout
|
||||
if effectiveTimeout == 0 {
|
||||
// if we requested to wait forever, set it to a week.
|
||||
effectiveTimeout = 168 * time.Hour
|
||||
}
|
||||
waitOptions := kubectlwait.WaitOptions{
|
||||
ResourceFinder: genericclioptions.ResourceFinderForResult(resource.InfoListVisitor(deletedInfos)),
|
||||
DynamicClient: o.DynamicClient,
|
||||
Timeout: effectiveTimeout,
|
||||
|
||||
Printer: printers.NewDiscardingPrinter(),
|
||||
ConditionFn: kubectlwait.IsDeleted,
|
||||
IOStreams: o.IOStreams,
|
||||
}
|
||||
err = waitOptions.RunWait()
|
||||
if errors.IsForbidden(err) {
|
||||
// if we're forbidden from waiting, we shouldn't fail.
|
||||
glog.V(1).Info(err)
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func cascadingDeleteResource(info *resource.Info, out io.Writer, shortOutput bool) error {
|
||||
falseVar := false
|
||||
deleteOptions := &metav1.DeleteOptions{OrphanDependents: &falseVar}
|
||||
return deleteResource(info, out, shortOutput, deleteOptions)
|
||||
}
|
||||
func (o *DeleteOptions) deleteResource(info *resource.Info, deleteOptions *metav1.DeleteOptions) error {
|
||||
// TODO: Remove this in or after 1.12 release.
|
||||
// Server version >= 1.11 no longer needs this hack.
|
||||
mapping := info.ResourceMapping()
|
||||
if mapping.Resource.GroupResource() == (schema.GroupResource{Group: "extensions", Resource: "daemonsets"}) ||
|
||||
mapping.Resource.GroupResource() == (schema.GroupResource{Group: "apps", Resource: "daemonsets"}) {
|
||||
if err := updateDaemonSet(info.Namespace, info.Name, o.DynamicClient); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func deleteResource(info *resource.Info, out io.Writer, shortOutput bool, deleteOptions *metav1.DeleteOptions) error {
|
||||
if err := resource.NewHelper(info.Client, info.Mapping).DeleteWithOptions(info.Namespace, info.Name, deleteOptions); err != nil {
|
||||
return cmdutil.AddSourceToErr("deleting", info.Source, err)
|
||||
}
|
||||
|
||||
printDeletion(info, out, shortOutput)
|
||||
o.PrintObj(info)
|
||||
return nil
|
||||
}
|
||||
|
||||
// deletion printing is special because they don't have an object to print. This logic mirrors PrintSuccess
|
||||
func printDeletion(info *resource.Info, out io.Writer, shortOutput bool) {
|
||||
// TODO: Remove this in or after 1.12 release.
|
||||
// Server version >= 1.11 no longer needs this hack.
|
||||
func updateDaemonSet(namespace, name string, dynamicClient dynamic.Interface) error {
|
||||
dsClient := dynamicClient.Resource(schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "daemonsets"}).Namespace(namespace)
|
||||
obj, err := dsClient.Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ds := &appsv1.DaemonSet{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, ds); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// We set the nodeSelector to a random label. This label is nearly guaranteed
|
||||
// to not be set on any node so the DameonSetController will start deleting
|
||||
// daemon pods. Once it's done deleting the daemon pods, it's safe to delete
|
||||
// the DaemonSet.
|
||||
ds.Spec.Template.Spec.NodeSelector = map[string]string{
|
||||
string(uuid.NewUUID()): string(uuid.NewUUID()),
|
||||
}
|
||||
// force update to avoid version conflict
|
||||
ds.ResourceVersion = ""
|
||||
|
||||
out, err := runtime.DefaultUnstructuredConverter.ToUnstructured(ds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = dsClient.Update(&unstructured.Unstructured{Object: out}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for the daemon set controller to kill all the daemon pods.
|
||||
if err := wait.Poll(1*time.Second, 5*time.Minute, func() (bool, error) {
|
||||
updatedObj, err := dsClient.Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
updatedDS := &appsv1.DaemonSet{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(updatedObj.Object, ds); err != nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return updatedDS.Status.CurrentNumberScheduled+updatedDS.Status.NumberMisscheduled == 0, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// deletion printing is special because we do not have an object to print.
|
||||
// This mirrors name printer behavior
|
||||
func (o *DeleteOptions) PrintObj(info *resource.Info) {
|
||||
operation := "deleted"
|
||||
groupKind := info.Mapping.GroupVersionKind
|
||||
kindString := fmt.Sprintf("%s.%s", strings.ToLower(groupKind.Kind), groupKind.Group)
|
||||
@ -329,33 +371,16 @@ func printDeletion(info *resource.Info, out io.Writer, shortOutput bool) {
|
||||
kindString = strings.ToLower(groupKind.Kind)
|
||||
}
|
||||
|
||||
if shortOutput {
|
||||
if o.GracePeriod == 0 {
|
||||
operation = "force deleted"
|
||||
}
|
||||
|
||||
if o.Output == "name" {
|
||||
// -o name: prints resource/name
|
||||
fmt.Fprintf(out, "%s/%s\n", kindString, info.Name)
|
||||
fmt.Fprintf(o.Out, "%s/%s\n", kindString, info.Name)
|
||||
return
|
||||
}
|
||||
|
||||
// understandable output by default
|
||||
fmt.Fprintf(out, "%s \"%s\" %s\n", kindString, info.Name, operation)
|
||||
}
|
||||
|
||||
// objectDeletionWaitInterval is the interval to wait between checks for deletion.
|
||||
var objectDeletionWaitInterval = time.Second
|
||||
|
||||
// waitForObjectDeletion refreshes the object, waiting until it is deleted, a timeout is reached, or
|
||||
// an error is encountered. It checks once a second.
|
||||
func waitForObjectDeletion(info *resource.Info, timeout time.Duration) error {
|
||||
copied := *info
|
||||
info = &copied
|
||||
// TODO: refactor Reaper so that we can pass the "wait" option into it, and then check for UID change.
|
||||
return wait.PollImmediate(objectDeletionWaitInterval, timeout, func() (bool, error) {
|
||||
switch err := info.Get(); {
|
||||
case err == nil:
|
||||
return false, nil
|
||||
case errors.IsNotFound(err):
|
||||
return true, nil
|
||||
default:
|
||||
return false, err
|
||||
}
|
||||
})
|
||||
fmt.Fprintf(o.Out, "%s \"%s\" %s\n", kindString, info.Name, operation)
|
||||
}
|
||||
|
193
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/delete_flags.go
generated
vendored
Normal file
193
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/delete_flags.go
generated
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
Copyright 2018 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 cmd
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
// PrintFlags composes common printer flag structs
|
||||
// used for commands requiring deletion logic.
|
||||
type DeleteFlags struct {
|
||||
FileNameFlags *genericclioptions.FileNameFlags
|
||||
LabelSelector *string
|
||||
FieldSelector *string
|
||||
|
||||
All *bool
|
||||
Cascade *bool
|
||||
Force *bool
|
||||
GracePeriod *int
|
||||
IgnoreNotFound *bool
|
||||
Now *bool
|
||||
Timeout *time.Duration
|
||||
Wait *bool
|
||||
Output *string
|
||||
}
|
||||
|
||||
func (f *DeleteFlags) ToOptions(dynamicClient dynamic.Interface, streams genericclioptions.IOStreams) *DeleteOptions {
|
||||
options := &DeleteOptions{
|
||||
DynamicClient: dynamicClient,
|
||||
IOStreams: streams,
|
||||
}
|
||||
|
||||
// add filename options
|
||||
if f.FileNameFlags != nil {
|
||||
options.FilenameOptions = f.FileNameFlags.ToOptions()
|
||||
}
|
||||
if f.LabelSelector != nil {
|
||||
options.LabelSelector = *f.LabelSelector
|
||||
}
|
||||
if f.FieldSelector != nil {
|
||||
options.FieldSelector = *f.FieldSelector
|
||||
}
|
||||
|
||||
// add output format
|
||||
if f.Output != nil {
|
||||
options.Output = *f.Output
|
||||
}
|
||||
|
||||
if f.All != nil {
|
||||
options.DeleteAll = *f.All
|
||||
}
|
||||
if f.Cascade != nil {
|
||||
options.Cascade = *f.Cascade
|
||||
}
|
||||
if f.Force != nil {
|
||||
options.ForceDeletion = *f.Force
|
||||
}
|
||||
if f.GracePeriod != nil {
|
||||
options.GracePeriod = *f.GracePeriod
|
||||
}
|
||||
if f.IgnoreNotFound != nil {
|
||||
options.IgnoreNotFound = *f.IgnoreNotFound
|
||||
}
|
||||
if f.Now != nil {
|
||||
options.DeleteNow = *f.Now
|
||||
}
|
||||
if f.Timeout != nil {
|
||||
options.Timeout = *f.Timeout
|
||||
}
|
||||
if f.Wait != nil {
|
||||
options.WaitForDeletion = *f.Wait
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
func (f *DeleteFlags) AddFlags(cmd *cobra.Command) {
|
||||
f.FileNameFlags.AddFlags(cmd.Flags())
|
||||
if f.LabelSelector != nil {
|
||||
cmd.Flags().StringVarP(f.LabelSelector, "selector", "l", *f.LabelSelector, "Selector (label query) to filter on, not including uninitialized ones.")
|
||||
}
|
||||
if f.FieldSelector != nil {
|
||||
cmd.Flags().StringVarP(f.FieldSelector, "field-selector", "", *f.FieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.")
|
||||
}
|
||||
if f.All != nil {
|
||||
cmd.Flags().BoolVar(f.All, "all", *f.All, "Delete all resources, including uninitialized ones, in the namespace of the specified resource types.")
|
||||
}
|
||||
if f.Force != nil {
|
||||
cmd.Flags().BoolVar(f.Force, "force", *f.Force, "Only used when grace-period=0. If true, immediately remove resources from API and bypass graceful deletion. Note that immediate deletion of some resources may result in inconsistency or data loss and requires confirmation.")
|
||||
}
|
||||
if f.Cascade != nil {
|
||||
cmd.Flags().BoolVar(f.Cascade, "cascade", *f.Cascade, "If true, cascade the deletion of the resources managed by this resource (e.g. Pods created by a ReplicationController). Default true.")
|
||||
}
|
||||
if f.Now != nil {
|
||||
cmd.Flags().BoolVar(f.Now, "now", *f.Now, "If true, resources are signaled for immediate shutdown (same as --grace-period=1).")
|
||||
}
|
||||
if f.GracePeriod != nil {
|
||||
cmd.Flags().IntVar(f.GracePeriod, "grace-period", *f.GracePeriod, "Period of time in seconds given to the resource to terminate gracefully. Ignored if negative. Set to 1 for immediate shutdown. Can only be set to 0 when --force is true (force deletion).")
|
||||
}
|
||||
if f.Timeout != nil {
|
||||
cmd.Flags().DurationVar(f.Timeout, "timeout", *f.Timeout, "The length of time to wait before giving up on a delete, zero means determine a timeout from the size of the object")
|
||||
}
|
||||
if f.IgnoreNotFound != nil {
|
||||
cmd.Flags().BoolVar(f.IgnoreNotFound, "ignore-not-found", *f.IgnoreNotFound, "Treat \"resource not found\" as a successful delete. Defaults to \"true\" when --all is specified.")
|
||||
}
|
||||
if f.Wait != nil {
|
||||
cmd.Flags().BoolVar(f.Wait, "wait", *f.Wait, "If true, wait for resources to be gone before returning. This waits for finalizers.")
|
||||
}
|
||||
if f.Output != nil {
|
||||
cmd.Flags().StringVarP(f.Output, "output", "o", *f.Output, "Output mode. Use \"-o name\" for shorter output (resource/name).")
|
||||
}
|
||||
}
|
||||
|
||||
// NewDeleteCommandFlags provides default flags and values for use with the "delete" command
|
||||
func NewDeleteCommandFlags(usage string) *DeleteFlags {
|
||||
cascade := true
|
||||
gracePeriod := -1
|
||||
|
||||
// setup command defaults
|
||||
all := false
|
||||
force := false
|
||||
ignoreNotFound := false
|
||||
now := false
|
||||
output := ""
|
||||
labelSelector := ""
|
||||
fieldSelector := ""
|
||||
timeout := time.Duration(0)
|
||||
wait := true
|
||||
|
||||
filenames := []string{}
|
||||
recursive := false
|
||||
|
||||
return &DeleteFlags{
|
||||
FileNameFlags: &genericclioptions.FileNameFlags{Usage: usage, Filenames: &filenames, Recursive: &recursive},
|
||||
LabelSelector: &labelSelector,
|
||||
FieldSelector: &fieldSelector,
|
||||
|
||||
Cascade: &cascade,
|
||||
GracePeriod: &gracePeriod,
|
||||
|
||||
All: &all,
|
||||
Force: &force,
|
||||
IgnoreNotFound: &ignoreNotFound,
|
||||
Now: &now,
|
||||
Timeout: &timeout,
|
||||
Wait: &wait,
|
||||
Output: &output,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDeleteFlags provides default flags and values for use in commands outside of "delete"
|
||||
func NewDeleteFlags(usage string) *DeleteFlags {
|
||||
cascade := true
|
||||
gracePeriod := -1
|
||||
|
||||
force := false
|
||||
timeout := time.Duration(0)
|
||||
wait := false
|
||||
|
||||
filenames := []string{}
|
||||
recursive := false
|
||||
|
||||
return &DeleteFlags{
|
||||
FileNameFlags: &genericclioptions.FileNameFlags{Usage: usage, Filenames: &filenames, Recursive: &recursive},
|
||||
|
||||
Cascade: &cascade,
|
||||
GracePeriod: &gracePeriod,
|
||||
|
||||
// add non-defaults
|
||||
Force: &force,
|
||||
Timeout: &timeout,
|
||||
Wait: &wait,
|
||||
}
|
||||
}
|
295
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/delete_test.go
generated
vendored
295
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/delete_test.go
generated
vendored
@ -17,47 +17,45 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
var unstructuredSerializer = dynamic.ContentConfig().NegotiatedSerializer
|
||||
var unstructuredSerializer = resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer
|
||||
|
||||
var fakecmd = &cobra.Command{
|
||||
Use: "delete ([-f FILENAME] | TYPE [(NAME | -l label | --all)])",
|
||||
DisableFlagsInUseLine: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
|
||||
},
|
||||
func fakecmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "delete ([-f FILENAME] | TYPE [(NAME | -l label | --all)])",
|
||||
DisableFlagsInUseLine: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func TestDeleteObjectByTuple(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, _, rc := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -79,10 +77,9 @@ func TestDeleteObjectByTuple(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -92,8 +89,8 @@ func TestDeleteObjectByTuple(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test cascading delete of object without client-side reaper doesn't make GET requests
|
||||
buf, errBuf = bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
cmd = NewCmdDelete(tf, buf, errBuf)
|
||||
streams, _, buf, _ = genericclioptions.NewTestIOStreams()
|
||||
cmd = NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{"secrets/mysecret"})
|
||||
@ -102,17 +99,17 @@ func TestDeleteObjectByTuple(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func hasExpectedOrphanDependents(body io.ReadCloser, expectedOrphanDependents *bool) bool {
|
||||
if body == nil || expectedOrphanDependents == nil {
|
||||
return body == nil && expectedOrphanDependents == nil
|
||||
func hasExpectedPropagationPolicy(body io.ReadCloser, policy *metav1.DeletionPropagation) bool {
|
||||
if body == nil || policy == nil {
|
||||
return body == nil && policy == nil
|
||||
}
|
||||
var parsedBody metav1.DeleteOptions
|
||||
rawBody, _ := ioutil.ReadAll(body)
|
||||
json.Unmarshal(rawBody, &parsedBody)
|
||||
if parsedBody.OrphanDependents == nil {
|
||||
if parsedBody.PropagationPolicy == nil {
|
||||
return false
|
||||
}
|
||||
return *expectedOrphanDependents == *parsedBody.OrphanDependents
|
||||
return *policy == *parsedBody.PropagationPolicy
|
||||
}
|
||||
|
||||
// Tests that DeleteOptions.OrphanDependents is appropriately set while deleting objects.
|
||||
@ -120,16 +117,18 @@ func TestOrphanDependentsInDeleteObject(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, _, rc := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
var expectedOrphanDependents *bool
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
var policy *metav1.DeletionPropagation
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m, b := req.URL.Path, req.Method, req.Body; {
|
||||
|
||||
case p == "/namespaces/test/secrets/mysecret" && m == "DELETE" && hasExpectedOrphanDependents(b, expectedOrphanDependents):
|
||||
case p == "/namespaces/test/secrets/mysecret" && m == "DELETE" && hasExpectedPropagationPolicy(b, policy):
|
||||
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &rc.Items[0])}, nil
|
||||
default:
|
||||
@ -137,13 +136,12 @@ func TestOrphanDependentsInDeleteObject(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
|
||||
// DeleteOptions.OrphanDependents should be false, when cascade is true (default).
|
||||
falseVar := false
|
||||
expectedOrphanDependents = &falseVar
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
// DeleteOptions.PropagationPolicy should be Background, when cascade is true (default).
|
||||
backgroundPolicy := metav1.DeletePropagationBackground
|
||||
policy = &backgroundPolicy
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{"secrets/mysecret"})
|
||||
@ -152,10 +150,10 @@ func TestOrphanDependentsInDeleteObject(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test that delete options should be set to orphan when cascade is false.
|
||||
trueVar := true
|
||||
expectedOrphanDependents = &trueVar
|
||||
buf, errBuf = bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
cmd = NewCmdDelete(tf, buf, errBuf)
|
||||
orphanPolicy := metav1.DeletePropagationOrphan
|
||||
policy = &orphanPolicy
|
||||
streams, _, buf, _ = genericclioptions.NewTestIOStreams()
|
||||
cmd = NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -170,8 +168,10 @@ func TestDeleteNamedObject(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, _, rc := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -193,10 +193,9 @@ func TestDeleteNamedObject(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -206,8 +205,8 @@ func TestDeleteNamedObject(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test cascading delete of object without client-side reaper doesn't make GET requests
|
||||
buf, errBuf = bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
cmd = NewCmdDelete(tf, buf, errBuf)
|
||||
streams, _, buf, _ = genericclioptions.NewTestIOStreams()
|
||||
cmd = NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -221,8 +220,10 @@ func TestDeleteObject(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, _, rc := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -236,11 +237,10 @@ func TestDeleteObject(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy/redis-master-controller.yaml")
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("filename", "../../../test/e2e/testing-manifests/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{})
|
||||
@ -251,37 +251,15 @@ func TestDeleteObject(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type fakeReaper struct {
|
||||
namespace, name string
|
||||
timeout time.Duration
|
||||
deleteOptions *metav1.DeleteOptions
|
||||
err error
|
||||
}
|
||||
|
||||
func (r *fakeReaper) Stop(namespace, name string, timeout time.Duration, gracePeriod *metav1.DeleteOptions) error {
|
||||
r.namespace, r.name = namespace, name
|
||||
r.timeout = timeout
|
||||
r.deleteOptions = gracePeriod
|
||||
return r.err
|
||||
}
|
||||
|
||||
type fakeReaperFactory struct {
|
||||
cmdutil.Factory
|
||||
reaper kubectl.Reaper
|
||||
}
|
||||
|
||||
func (f *fakeReaperFactory) Reaper(mapping *meta.RESTMapping) (kubectl.Reaper, error) {
|
||||
return f.reaper, nil
|
||||
}
|
||||
|
||||
func TestDeleteObjectGraceZero(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
pods, _, _ := testData()
|
||||
|
||||
objectDeletionWaitInterval = time.Millisecond
|
||||
count := 0
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -306,12 +284,9 @@ func TestDeleteObjectGraceZero(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
|
||||
reaper := &fakeReaper{}
|
||||
fake := &fakeReaperFactory{Factory: tf, reaper: reaper}
|
||||
cmd := NewCmdDelete(fake, buf, errBuf)
|
||||
streams, _, buf, errBuf := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Flags().Set("grace-period", "0")
|
||||
cmd.Run(cmd, []string{"pods/nginx"})
|
||||
@ -320,17 +295,16 @@ func TestDeleteObjectGraceZero(t *testing.T) {
|
||||
if buf.String() != "pod/nginx\n" {
|
||||
t.Errorf("unexpected output: %s\n---\n%s", buf.String(), errBuf.String())
|
||||
}
|
||||
if reaper.deleteOptions == nil || reaper.deleteOptions.GracePeriodSeconds == nil || *reaper.deleteOptions.GracePeriodSeconds != 1 {
|
||||
t.Errorf("unexpected reaper options: %#v", reaper)
|
||||
}
|
||||
if count != 4 {
|
||||
if count != 0 {
|
||||
t.Errorf("unexpected calls to GET: %d", count)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteObjectNotFound(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
@ -343,18 +317,17 @@ func TestDeleteObjectNotFound(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
|
||||
options := &DeleteOptions{
|
||||
FilenameOptions: resource.FilenameOptions{
|
||||
Filenames: []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml"},
|
||||
Filenames: []string{"../../../test/e2e/testing-manifests/guestbook/legacy/redis-master-controller.yaml"},
|
||||
},
|
||||
GracePeriod: -1,
|
||||
Cascade: false,
|
||||
Output: "name",
|
||||
IOStreams: genericclioptions.NewTestIOStreamsDiscard(),
|
||||
}
|
||||
err := options.Complete(tf, buf, errBuf, []string{}, fakecmd)
|
||||
err := options.Complete(tf, []string{}, fakecmd())
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@ -366,7 +339,9 @@ func TestDeleteObjectNotFound(t *testing.T) {
|
||||
|
||||
func TestDeleteObjectIgnoreNotFound(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
@ -379,11 +354,10 @@ func TestDeleteObjectIgnoreNotFound(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("filename", "../../../test/e2e/testing-manifests/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("ignore-not-found", "true")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -401,8 +375,10 @@ func TestDeleteAllNotFound(t *testing.T) {
|
||||
svc.Items = append(svc.Items, api.Service{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
|
||||
notFoundError := &errors.NewNotFound(api.Resource("services"), "foo").ErrStatus
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -420,8 +396,6 @@ func TestDeleteAllNotFound(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
|
||||
// Make sure we can explicitly choose to fail on NotFound errors, even with --all
|
||||
options := &DeleteOptions{
|
||||
@ -431,8 +405,9 @@ func TestDeleteAllNotFound(t *testing.T) {
|
||||
DeleteAll: true,
|
||||
IgnoreNotFound: false,
|
||||
Output: "name",
|
||||
IOStreams: genericclioptions.NewTestIOStreamsDiscard(),
|
||||
}
|
||||
err := options.Complete(tf, buf, errBuf, []string{"services"}, fakecmd)
|
||||
err := options.Complete(tf, []string{"services"}, fakecmd())
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@ -446,8 +421,10 @@ func TestDeleteAllIgnoreNotFound(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, svc, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
// Add an item to the list which will result in a 404 on delete
|
||||
svc.Items = append(svc.Items, api.Service{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
|
||||
@ -469,10 +446,9 @@ func TestDeleteAllIgnoreNotFound(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("all", "true")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -487,8 +463,10 @@ func TestDeleteMultipleObject(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, svc, rc := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -504,12 +482,11 @@ func TestDeleteMultipleObject(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/frontend-service.yaml")
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("filename", "../../../test/e2e/testing-manifests/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Flags().Set("filename", "../../../test/e2e/testing-manifests/guestbook/frontend-service.yaml")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{})
|
||||
@ -523,8 +500,10 @@ func TestDeleteMultipleObjectContinueOnMissing(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, svc, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -540,18 +519,18 @@ func TestDeleteMultipleObjectContinueOnMissing(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
options := &DeleteOptions{
|
||||
FilenameOptions: resource.FilenameOptions{
|
||||
Filenames: []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml", "../../../examples/guestbook/frontend-service.yaml"},
|
||||
Filenames: []string{"../../../test/e2e/testing-manifests/guestbook/legacy/redis-master-controller.yaml", "../../../test/e2e/testing-manifests/guestbook/frontend-service.yaml"},
|
||||
},
|
||||
GracePeriod: -1,
|
||||
Cascade: false,
|
||||
Output: "name",
|
||||
IOStreams: streams,
|
||||
}
|
||||
err := options.Complete(tf, buf, errBuf, []string{}, fakecmd)
|
||||
err := options.Complete(tf, []string{}, fakecmd())
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@ -568,8 +547,10 @@ func TestDeleteMultipleObjectContinueOnMissing(t *testing.T) {
|
||||
func TestDeleteMultipleResourcesWithTheSameName(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, svc, rc := testData()
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -590,10 +571,9 @@ func TestDeleteMultipleResourcesWithTheSameName(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -607,8 +587,10 @@ func TestDeleteDirectory(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
_, _, rc := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -622,11 +604,10 @@ func TestDeleteDirectory(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy")
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("filename", "../../../test/e2e/testing-manifests/guestbook/legacy")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Run(cmd, []string{})
|
||||
@ -640,8 +621,10 @@ func TestDeleteMultipleSelector(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
pods, svc, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -667,10 +650,9 @@ func TestDeleteMultipleSelector(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDelete(tf, buf, errBuf)
|
||||
cmd := NewCmdDelete(tf, streams)
|
||||
cmd.Flags().Set("selector", "a=b")
|
||||
cmd.Flags().Set("cascade", "false")
|
||||
cmd.Flags().Set("output", "name")
|
||||
@ -706,26 +688,29 @@ func TestResourceErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
for k, testCase := range testCases {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
t.Run(k, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
options := &DeleteOptions{
|
||||
FilenameOptions: resource.FilenameOptions{},
|
||||
GracePeriod: -1,
|
||||
Cascade: false,
|
||||
Output: "name",
|
||||
}
|
||||
err := options.Complete(tf, buf, errBuf, testCase.args, fakecmd)
|
||||
if !testCase.errFn(err) {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
continue
|
||||
}
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
options := &DeleteOptions{
|
||||
FilenameOptions: resource.FilenameOptions{},
|
||||
GracePeriod: -1,
|
||||
Cascade: false,
|
||||
Output: "name",
|
||||
IOStreams: streams,
|
||||
}
|
||||
err := options.Complete(tf, testCase.args, fakecmd())
|
||||
if !testCase.errFn(err) {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
return
|
||||
}
|
||||
|
||||
if buf.Len() > 0 {
|
||||
t.Errorf("buffer should be empty: %s", string(buf.Bytes()))
|
||||
}
|
||||
if buf.Len() > 0 {
|
||||
t.Errorf("buffer should be empty: %s", string(buf.Bytes()))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
137
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/describe.go
generated
vendored
137
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/describe.go
generated
vendored
@ -18,21 +18,20 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -69,67 +68,103 @@ var (
|
||||
kubectl describe pods frontend`))
|
||||
)
|
||||
|
||||
func NewCmdDescribe(f cmdutil.Factory, out, cmdErr io.Writer) *cobra.Command {
|
||||
options := &resource.FilenameOptions{}
|
||||
describerSettings := &printers.DescriberSettings{}
|
||||
type DescribeOptions struct {
|
||||
CmdParent string
|
||||
Selector string
|
||||
Namespace string
|
||||
|
||||
// TODO: this should come from the factory, and may need to be loaded from the server, and so is probably
|
||||
// going to have to be removed
|
||||
validArgs := printersinternal.DescribableResources()
|
||||
argAliases := kubectl.ResourceAliases(validArgs)
|
||||
Describer func(*meta.RESTMapping) (printers.Describer, error)
|
||||
NewBuilder func() *resource.Builder
|
||||
|
||||
BuilderArgs []string
|
||||
|
||||
EnforceNamespace bool
|
||||
AllNamespaces bool
|
||||
IncludeUninitialized bool
|
||||
|
||||
DescriberSettings *printers.DescriberSettings
|
||||
FilenameOptions *resource.FilenameOptions
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewCmdDescribe(parent string, f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := &DescribeOptions{
|
||||
FilenameOptions: &resource.FilenameOptions{},
|
||||
DescriberSettings: &printers.DescriberSettings{
|
||||
ShowEvents: true,
|
||||
},
|
||||
|
||||
CmdParent: parent,
|
||||
|
||||
IOStreams: streams,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME)",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Show details of a specific resource or group of resources"),
|
||||
Long: describeLong + "\n\n" + cmdutil.ValidResourceTypeList(f),
|
||||
Long: describeLong + "\n\n" + cmdutil.SuggestApiResources(parent),
|
||||
Example: describeExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := RunDescribe(f, out, cmdErr, cmd, args, options, describerSettings)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: argAliases,
|
||||
}
|
||||
usage := "containing the resource to describe"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, options, usage)
|
||||
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().Bool("all-namespaces", false, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
|
||||
cmd.Flags().BoolVar(&describerSettings.ShowEvents, "show-events", true, "If true, display events related to the described object.")
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, usage)
|
||||
cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().BoolVar(&o.AllNamespaces, "all-namespaces", o.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
|
||||
cmd.Flags().BoolVar(&o.DescriberSettings.ShowEvents, "show-events", o.DescriberSettings.ShowEvents, "If true, display events related to the described object.")
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions, describerSettings *printers.DescriberSettings) error {
|
||||
selector := cmdutil.GetFlagString(cmd, "selector")
|
||||
allNamespaces := cmdutil.GetFlagBool(cmd, "all-namespaces")
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
func (o *DescribeOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
var err error
|
||||
o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if allNamespaces {
|
||||
enforceNamespace = false
|
||||
|
||||
if o.AllNamespaces {
|
||||
o.EnforceNamespace = false
|
||||
}
|
||||
if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(options.Filenames) {
|
||||
fmt.Fprint(cmdErr, "You must specify the type of resource to describe. ", cmdutil.ValidResourceTypeList(f))
|
||||
return cmdutil.UsageErrorf(cmd, "Required resource not specified.")
|
||||
|
||||
if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames) {
|
||||
return fmt.Errorf("You must specify the type of resource to describe. %s\n", cmdutil.SuggestApiResources(o.CmdParent))
|
||||
}
|
||||
|
||||
o.BuilderArgs = args
|
||||
|
||||
o.Describer = func(mapping *meta.RESTMapping) (printers.Describer, error) {
|
||||
return cmdutil.DescriberFn(f, mapping)
|
||||
}
|
||||
|
||||
o.NewBuilder = f.NewBuilder
|
||||
|
||||
// include the uninitialized objects by default
|
||||
// unless user explicitly set --include-uninitialized=false
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, true)
|
||||
r := f.NewBuilder().
|
||||
o.IncludeUninitialized = cmdutil.ShouldIncludeUninitialized(cmd, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *DescribeOptions) Validate(args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *DescribeOptions) Run() error {
|
||||
r := o.NewBuilder().
|
||||
Unstructured().
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
|
||||
FilenameParam(enforceNamespace, options).
|
||||
LabelSelectorParam(selector).
|
||||
IncludeUninitialized(includeUninitialized).
|
||||
ResourceTypeOrNameArgs(true, args...).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().AllNamespaces(o.AllNamespaces).
|
||||
FilenameParam(o.EnforceNamespace, o.FilenameOptions).
|
||||
LabelSelectorParam(o.Selector).
|
||||
IncludeUninitialized(o.IncludeUninitialized).
|
||||
ResourceTypeOrNameArgs(true, o.BuilderArgs...).
|
||||
Flatten().
|
||||
Do()
|
||||
err = r.Err()
|
||||
err := r.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -137,8 +172,8 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
|
||||
allErrs := []error{}
|
||||
infos, err := r.Infos()
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) && len(args) == 2 {
|
||||
return DescribeMatchingResources(f, cmdNamespace, args[0], args[1], describerSettings, out, err)
|
||||
if apierrors.IsNotFound(err) && len(o.BuilderArgs) == 2 {
|
||||
return o.DescribeMatchingResources(err, o.BuilderArgs[0], o.BuilderArgs[1])
|
||||
}
|
||||
allErrs = append(allErrs, err)
|
||||
}
|
||||
@ -147,7 +182,7 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
|
||||
first := true
|
||||
for _, info := range infos {
|
||||
mapping := info.ResourceMapping()
|
||||
describer, err := f.Describer(mapping)
|
||||
describer, err := o.Describer(mapping)
|
||||
if err != nil {
|
||||
if errs.Has(err.Error()) {
|
||||
continue
|
||||
@ -156,7 +191,7 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
|
||||
errs.Insert(err.Error())
|
||||
continue
|
||||
}
|
||||
s, err := describer.Describe(info.Namespace, info.Name, *describerSettings)
|
||||
s, err := describer.Describe(info.Namespace, info.Name, *o.DescriberSettings)
|
||||
if err != nil {
|
||||
if errs.Has(err.Error()) {
|
||||
continue
|
||||
@ -167,20 +202,20 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
|
||||
}
|
||||
if first {
|
||||
first = false
|
||||
fmt.Fprint(out, s)
|
||||
fmt.Fprint(o.Out, s)
|
||||
} else {
|
||||
fmt.Fprintf(out, "\n\n%s", s)
|
||||
fmt.Fprintf(o.Out, "\n\n%s", s)
|
||||
}
|
||||
}
|
||||
|
||||
return utilerrors.NewAggregate(allErrs)
|
||||
}
|
||||
|
||||
func DescribeMatchingResources(f cmdutil.Factory, namespace, rsrc, prefix string, describerSettings *printers.DescriberSettings, out io.Writer, originalError error) error {
|
||||
r := f.NewBuilder().
|
||||
func (o *DescribeOptions) DescribeMatchingResources(originalError error, resource, prefix string) error {
|
||||
r := o.NewBuilder().
|
||||
Unstructured().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
ResourceTypeOrNameArgs(true, rsrc).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
ResourceTypeOrNameArgs(true, resource).
|
||||
SingleResourceType().
|
||||
Flatten().
|
||||
Do()
|
||||
@ -188,7 +223,7 @@ func DescribeMatchingResources(f cmdutil.Factory, namespace, rsrc, prefix string
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
describer, err := f.Describer(mapping)
|
||||
describer, err := o.Describer(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -201,11 +236,11 @@ func DescribeMatchingResources(f cmdutil.Factory, namespace, rsrc, prefix string
|
||||
info := infos[ix]
|
||||
if strings.HasPrefix(info.Name, prefix) {
|
||||
isFound = true
|
||||
s, err := describer.Describe(info.Namespace, info.Name, *describerSettings)
|
||||
s, err := describer.Describe(info.Namespace, info.Name, *o.DescriberSettings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(out, "%s\n", s)
|
||||
fmt.Fprintf(o.Out, "%s\n", s)
|
||||
}
|
||||
}
|
||||
if !isFound {
|
||||
|
155
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/describe_test.go
generated
vendored
155
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/describe_test.go
generated
vendored
@ -17,32 +17,42 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
|
||||
func TestDescribeUnknownSchemaObject(t *testing.T) {
|
||||
d := &testDescriber{Output: "test output"}
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
oldFn := cmdutil.DescriberFn
|
||||
defer func() {
|
||||
cmdutil.DescriberFn = oldFn
|
||||
}()
|
||||
cmdutil.DescriberFn = d.describerFor
|
||||
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("non-default")
|
||||
defer tf.Cleanup()
|
||||
_, _, codec := cmdtesting.NewExternalScheme()
|
||||
tf.DescriberVal = d
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalType("", "", "foo"))},
|
||||
}
|
||||
tf.Namespace = "non-default"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
buferr := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdDescribe(tf, buf, buferr)
|
||||
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDescribe("kubectl", tf, streams)
|
||||
cmd.Run(cmd, []string{"type", "foo"})
|
||||
|
||||
if d.Name != "foo" || d.Namespace != "" {
|
||||
@ -57,18 +67,25 @@ func TestDescribeUnknownSchemaObject(t *testing.T) {
|
||||
// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
|
||||
func TestDescribeUnknownNamespacedSchemaObject(t *testing.T) {
|
||||
d := &testDescriber{Output: "test output"}
|
||||
oldFn := cmdutil.DescriberFn
|
||||
defer func() {
|
||||
cmdutil.DescriberFn = oldFn
|
||||
}()
|
||||
cmdutil.DescriberFn = d.describerFor
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
_, _, codec := cmdtesting.NewExternalScheme()
|
||||
|
||||
tf.DescriberVal = d
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalNamespacedType("", "", "foo", "non-default"))},
|
||||
}
|
||||
tf.Namespace = "non-default"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
buferr := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdDescribe(tf, buf, buferr)
|
||||
tf.WithNamespace("non-default")
|
||||
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDescribe("kubectl", tf, streams)
|
||||
cmd.Run(cmd, []string{"namespacedtype", "foo"})
|
||||
|
||||
if d.Name != "foo" || d.Namespace != "non-default" {
|
||||
@ -81,12 +98,18 @@ func TestDescribeUnknownNamespacedSchemaObject(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDescribeObject(t *testing.T) {
|
||||
_, _, rc := testData()
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
|
||||
d := &testDescriber{Output: "test output"}
|
||||
tf.DescriberVal = d
|
||||
oldFn := cmdutil.DescriberFn
|
||||
defer func() {
|
||||
cmdutil.DescriberFn = oldFn
|
||||
}()
|
||||
cmdutil.DescriberFn = d.describerFor
|
||||
|
||||
_, _, rc := testData()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
@ -99,11 +122,11 @@ func TestDescribeObject(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
buferr := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdDescribe(tf, buf, buferr)
|
||||
cmd.Flags().Set("filename", "../../../examples/guestbook/legacy/redis-master-controller.yaml")
|
||||
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDescribe("kubectl", tf, streams)
|
||||
cmd.Flags().Set("filename", "../../../test/e2e/testing-manifests/guestbook/legacy/redis-master-controller.yaml")
|
||||
cmd.Run(cmd, []string{})
|
||||
|
||||
if d.Name != "redis-master" || d.Namespace != "test" {
|
||||
@ -116,21 +139,26 @@ func TestDescribeObject(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDescribeListObjects(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
|
||||
d := &testDescriber{Output: "test output"}
|
||||
tf.DescriberVal = d
|
||||
oldFn := cmdutil.DescriberFn
|
||||
defer func() {
|
||||
cmdutil.DescriberFn = oldFn
|
||||
}()
|
||||
cmdutil.DescriberFn = d.describerFor
|
||||
|
||||
pods, _, _ := testData()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
|
||||
}
|
||||
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
buferr := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdDescribe(tf, buf, buferr)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDescribe("kubectl", tf, streams)
|
||||
cmd.Run(cmd, []string{"pods"})
|
||||
if buf.String() != fmt.Sprintf("%s\n\n%s", d.Output, d.Output) {
|
||||
t.Errorf("unexpected output: %s", buf.String())
|
||||
@ -138,21 +166,24 @@ func TestDescribeListObjects(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDescribeObjectShowEvents(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
|
||||
d := &testDescriber{Output: "test output"}
|
||||
tf.DescriberVal = d
|
||||
oldFn := cmdutil.DescriberFn
|
||||
defer func() {
|
||||
cmdutil.DescriberFn = oldFn
|
||||
}()
|
||||
cmdutil.DescriberFn = d.describerFor
|
||||
|
||||
pods, _, _ := testData()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
|
||||
}
|
||||
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
buferr := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdDescribe(tf, buf, buferr)
|
||||
cmd := NewCmdDescribe("kubectl", tf, genericclioptions.NewTestIOStreamsDiscard())
|
||||
cmd.Flags().Set("show-events", "true")
|
||||
cmd.Run(cmd, []string{"pods"})
|
||||
if d.Settings.ShowEvents != true {
|
||||
@ -161,21 +192,24 @@ func TestDescribeObjectShowEvents(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDescribeObjectSkipEvents(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
|
||||
d := &testDescriber{Output: "test output"}
|
||||
tf.DescriberVal = d
|
||||
oldFn := cmdutil.DescriberFn
|
||||
defer func() {
|
||||
cmdutil.DescriberFn = oldFn
|
||||
}()
|
||||
cmdutil.DescriberFn = d.describerFor
|
||||
|
||||
pods, _, _ := testData()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
|
||||
}
|
||||
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
buferr := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdDescribe(tf, buf, buferr)
|
||||
cmd := NewCmdDescribe("kubectl", tf, genericclioptions.NewTestIOStreamsDiscard())
|
||||
cmd.Flags().Set("show-events", "false")
|
||||
cmd.Run(cmd, []string{"pods"})
|
||||
if d.Settings.ShowEvents != false {
|
||||
@ -185,10 +219,11 @@ func TestDescribeObjectSkipEvents(t *testing.T) {
|
||||
|
||||
func TestDescribeHelpMessage(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
buferr := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdDescribe(tf, buf, buferr)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdDescribe("kubectl", tf, streams)
|
||||
cmd.SetArgs([]string{"-h"})
|
||||
cmd.SetOutput(buf)
|
||||
_, err := cmd.ExecuteC()
|
||||
@ -209,3 +244,19 @@ func TestDescribeHelpMessage(t *testing.T) {
|
||||
t.Errorf("Expected not to contain: \n %v\nGot:\n %v\n", unexpected, got)
|
||||
}
|
||||
}
|
||||
|
||||
type testDescriber struct {
|
||||
Name, Namespace string
|
||||
Settings printers.DescriberSettings
|
||||
Output string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (t *testDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (output string, err error) {
|
||||
t.Namespace, t.Name = namespace, name
|
||||
t.Settings = describerSettings
|
||||
return t.Output, t.Err
|
||||
}
|
||||
func (t *testDescriber) describerFor(restClientGetter genericclioptions.RESTClientGetter, mapping *meta.RESTMapping) (printers.Describer, error) {
|
||||
return t, nil
|
||||
}
|
||||
|
97
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/diff.go
generated
vendored
97
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/diff.go
generated
vendored
@ -26,15 +26,18 @@ import (
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/dynamic"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/kubectl/apply/parse"
|
||||
"k8s.io/kubernetes/pkg/kubectl/apply/strategy"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/utils/exec"
|
||||
)
|
||||
@ -101,12 +104,11 @@ func parseDiffArguments(args []string) (string, string, error) {
|
||||
return from, to, nil
|
||||
}
|
||||
|
||||
func NewCmdDiff(f cmdutil.Factory, stdout, stderr io.Writer) *cobra.Command {
|
||||
func NewCmdDiff(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
var options DiffOptions
|
||||
diff := DiffProgram{
|
||||
Exec: exec.New(),
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
Exec: exec.New(),
|
||||
IOStreams: streams,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "diff -f FILENAME",
|
||||
@ -132,9 +134,8 @@ func NewCmdDiff(f cmdutil.Factory, stdout, stderr io.Writer) *cobra.Command {
|
||||
// KUBERNETES_EXTERNAL_DIFF environment variable will be used a diff
|
||||
// program. By default, `diff(1)` will be used.
|
||||
type DiffProgram struct {
|
||||
Exec exec.Interface
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
Exec exec.Interface
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func (d *DiffProgram) getCommand(args ...string) exec.Cmd {
|
||||
@ -147,8 +148,8 @@ func (d *DiffProgram) getCommand(args ...string) exec.Cmd {
|
||||
}
|
||||
|
||||
cmd := d.Exec.Command(diff, args...)
|
||||
cmd.SetStdout(d.Stdout)
|
||||
cmd.SetStderr(d.Stderr)
|
||||
cmd.SetStdout(d.Out)
|
||||
cmd.SetStderr(d.ErrOut)
|
||||
|
||||
return cmd
|
||||
}
|
||||
@ -264,6 +265,7 @@ type Object interface {
|
||||
// InfoObject is an implementation of the Object interface. It gets all
|
||||
// the information from the Info object.
|
||||
type InfoObject struct {
|
||||
Remote runtime.Unstructured
|
||||
Info *resource.Info
|
||||
Encoder runtime.Encoder
|
||||
Parser *parse.Factory
|
||||
@ -289,14 +291,10 @@ func (obj InfoObject) Local() (map[string]interface{}, error) {
|
||||
}
|
||||
|
||||
func (obj InfoObject) Live() (map[string]interface{}, error) {
|
||||
if obj.Info.Object == nil {
|
||||
if obj.Remote == nil {
|
||||
return nil, nil // Object doesn't exist on cluster.
|
||||
}
|
||||
data, err := runtime.Encode(obj.Encoder, obj.Info.Object)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.toMap(data)
|
||||
return obj.Remote.UnstructuredContent(), nil
|
||||
}
|
||||
|
||||
func (obj InfoObject) Merged() (map[string]interface{}, error) {
|
||||
@ -328,10 +326,10 @@ func (obj InfoObject) Merged() (map[string]interface{}, error) {
|
||||
}
|
||||
|
||||
func (obj InfoObject) Last() (map[string]interface{}, error) {
|
||||
if obj.Info.Object == nil {
|
||||
if obj.Remote == nil {
|
||||
return nil, nil // No object is live, return empty
|
||||
}
|
||||
accessor, err := meta.Accessor(obj.Info.Object)
|
||||
accessor, err := meta.Accessor(obj.Remote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -391,6 +389,50 @@ func (d *Differ) TearDown() {
|
||||
d.To.Dir.Delete() // Ignore error
|
||||
}
|
||||
|
||||
type Downloader struct {
|
||||
mapper meta.RESTMapper
|
||||
dclient dynamic.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
func NewDownloader(f cmdutil.Factory) (*Downloader, error) {
|
||||
var err error
|
||||
var d Downloader
|
||||
|
||||
d.mapper, err = f.ToRESTMapper()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.dclient, err = f.DynamicClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.ns, _, _ = f.ToRawKubeConfigLoader().Namespace()
|
||||
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
func (d *Downloader) Download(info *resource.Info) (*unstructured.Unstructured, error) {
|
||||
gvk := info.Object.GetObjectKind().GroupVersionKind()
|
||||
mapping, err := d.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resource dynamic.ResourceInterface
|
||||
switch mapping.Scope.Name() {
|
||||
case meta.RESTScopeNameNamespace:
|
||||
if info.Namespace == "" {
|
||||
info.Namespace = d.ns
|
||||
}
|
||||
resource = d.dclient.Resource(mapping.Resource).Namespace(info.Namespace)
|
||||
case meta.RESTScopeNameRoot:
|
||||
resource = d.dclient.Resource(mapping.Resource)
|
||||
}
|
||||
|
||||
return resource.Get(info.Name, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
// RunDiff uses the factory to parse file arguments, find the version to
|
||||
// diff, and find each Info object for each files, and runs against the
|
||||
// differ.
|
||||
@ -409,7 +451,7 @@ func RunDiff(f cmdutil.Factory, diff *DiffProgram, options *DiffOptions, from, t
|
||||
|
||||
printer := Printer{}
|
||||
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -418,25 +460,26 @@ func RunDiff(f cmdutil.Factory, diff *DiffProgram, options *DiffOptions, from, t
|
||||
Unstructured().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &options.FilenameOptions).
|
||||
Local().
|
||||
Flatten().
|
||||
Do()
|
||||
if err := r.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dl, err := NewDownloader(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := info.Get(); err != nil {
|
||||
if !errors.IsNotFound(err) {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%v\nfrom server for:", info), info.Source, err)
|
||||
}
|
||||
info.Object = nil
|
||||
}
|
||||
|
||||
remote, _ := dl.Download(info)
|
||||
obj := InfoObject{
|
||||
Remote: remote,
|
||||
Info: info,
|
||||
Parser: parser,
|
||||
Encoder: cmdutil.InternalVersionJSONEncoder(),
|
||||
|
8
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/diff_test.go
generated
vendored
8
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/diff_test.go
generated
vendored
@ -25,6 +25,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/utils/exec"
|
||||
)
|
||||
|
||||
@ -137,11 +138,10 @@ func TestArguments(t *testing.T) {
|
||||
|
||||
func TestDiffProgram(t *testing.T) {
|
||||
os.Setenv("KUBERNETES_EXTERNAL_DIFF", "echo")
|
||||
stdout := bytes.Buffer{}
|
||||
streams, _, stdout, _ := genericclioptions.NewTestIOStreams()
|
||||
diff := DiffProgram{
|
||||
Stdout: &stdout,
|
||||
Stderr: &bytes.Buffer{},
|
||||
Exec: exec.New(),
|
||||
IOStreams: streams,
|
||||
Exec: exec.New(),
|
||||
}
|
||||
err := diff.Run("one", "two")
|
||||
if err != nil {
|
||||
|
148
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/drain.go
generated
vendored
148
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/drain.go
generated
vendored
@ -19,7 +19,6 @@ package cmd
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
@ -30,7 +29,6 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
policyv1beta1 "k8s.io/api/policy/v1beta1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
@ -43,17 +41,24 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
type DrainOptions struct {
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
ToPrinter func(string) (printers.ResourcePrinterFunc, error)
|
||||
|
||||
Namespace string
|
||||
client kubernetes.Interface
|
||||
restClient *restclient.RESTClient
|
||||
Factory cmdutil.Factory
|
||||
Force bool
|
||||
DryRun bool
|
||||
GracePeriodSeconds int
|
||||
@ -63,11 +68,10 @@ type DrainOptions struct {
|
||||
DeleteLocalData bool
|
||||
Selector string
|
||||
PodSelector string
|
||||
mapper meta.RESTMapper
|
||||
nodeInfos []*resource.Info
|
||||
Out io.Writer
|
||||
ErrOut io.Writer
|
||||
typer runtime.ObjectTyper
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
// Takes a pod and returns a bool indicating whether or not to operate on the
|
||||
@ -101,8 +105,12 @@ var (
|
||||
kubectl cordon foo`))
|
||||
)
|
||||
|
||||
func NewCmdCordon(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := &DrainOptions{Factory: f, Out: out}
|
||||
func NewCmdCordon(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &DrainOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("cordoned").WithTypeSetter(scheme.Scheme),
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "cordon NODE",
|
||||
@ -111,7 +119,7 @@ func NewCmdCordon(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
Long: cordon_long,
|
||||
Example: cordon_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.SetupDrain(cmd, args))
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.RunCordonOrUncordon(true))
|
||||
},
|
||||
}
|
||||
@ -129,8 +137,11 @@ var (
|
||||
$ kubectl uncordon foo`))
|
||||
)
|
||||
|
||||
func NewCmdUncordon(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := &DrainOptions{Factory: f, Out: out}
|
||||
func NewCmdUncordon(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &DrainOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("uncordoned").WithTypeSetter(scheme.Scheme),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "uncordon NODE",
|
||||
@ -139,7 +150,7 @@ func NewCmdUncordon(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
Long: uncordon_long,
|
||||
Example: uncordon_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.SetupDrain(cmd, args))
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.RunCordonOrUncordon(false))
|
||||
},
|
||||
}
|
||||
@ -182,8 +193,18 @@ var (
|
||||
$ kubectl drain foo --grace-period=900`))
|
||||
)
|
||||
|
||||
func NewCmdDrain(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
options := &DrainOptions{Factory: f, Out: out, ErrOut: errOut, backOff: clockwork.NewRealClock()}
|
||||
func NewDrainOptions(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *DrainOptions {
|
||||
return &DrainOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("drained").WithTypeSetter(scheme.Scheme),
|
||||
|
||||
IOStreams: ioStreams,
|
||||
backOff: clockwork.NewRealClock(),
|
||||
GracePeriodSeconds: -1,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdDrain(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := NewDrainOptions(f, ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "drain NODE",
|
||||
@ -192,15 +213,15 @@ func NewCmdDrain(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
Long: drain_long,
|
||||
Example: drain_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.SetupDrain(cmd, args))
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.RunDrain())
|
||||
},
|
||||
}
|
||||
cmd.Flags().BoolVar(&options.Force, "force", false, "Continue even if there are pods not managed by a ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet.")
|
||||
cmd.Flags().BoolVar(&options.IgnoreDaemonsets, "ignore-daemonsets", false, "Ignore DaemonSet-managed pods.")
|
||||
cmd.Flags().BoolVar(&options.DeleteLocalData, "delete-local-data", false, "Continue even if there are pods using emptyDir (local data that will be deleted when the node is drained).")
|
||||
cmd.Flags().IntVar(&options.GracePeriodSeconds, "grace-period", -1, "Period of time in seconds given to each pod to terminate gracefully. If negative, the default value specified in the pod will be used.")
|
||||
cmd.Flags().DurationVar(&options.Timeout, "timeout", 0, "The length of time to wait before giving up, zero means infinite")
|
||||
cmd.Flags().BoolVar(&options.Force, "force", options.Force, "Continue even if there are pods not managed by a ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet.")
|
||||
cmd.Flags().BoolVar(&options.IgnoreDaemonsets, "ignore-daemonsets", options.IgnoreDaemonsets, "Ignore DaemonSet-managed pods.")
|
||||
cmd.Flags().BoolVar(&options.DeleteLocalData, "delete-local-data", options.DeleteLocalData, "Continue even if there are pods using emptyDir (local data that will be deleted when the node is drained).")
|
||||
cmd.Flags().IntVar(&options.GracePeriodSeconds, "grace-period", options.GracePeriodSeconds, "Period of time in seconds given to each pod to terminate gracefully. If negative, the default value specified in the pod will be used.")
|
||||
cmd.Flags().DurationVar(&options.Timeout, "timeout", options.Timeout, "The length of time to wait before giving up, zero means infinite")
|
||||
cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter on")
|
||||
cmd.Flags().StringVarP(&options.PodSelector, "pod-selector", "", options.PodSelector, "Label selector to filter pods on the node")
|
||||
|
||||
@ -208,11 +229,10 @@ func NewCmdDrain(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
// SetupDrain populates some fields from the factory, grabs command line
|
||||
// Complete populates some fields from the factory, grabs command line
|
||||
// arguments and looks up the node using Builder
|
||||
func (o *DrainOptions) SetupDrain(cmd *cobra.Command, args []string) error {
|
||||
func (o *DrainOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
var err error
|
||||
o.Selector = cmdutil.GetFlagString(cmd, "selector")
|
||||
|
||||
if len(args) == 0 && !cmd.Flags().Changed("selector") {
|
||||
return cmdutil.UsageErrorf(cmd, fmt.Sprintf("USAGE: %s [flags]", cmd.Use))
|
||||
@ -226,7 +246,7 @@ func (o *DrainOptions) SetupDrain(cmd *cobra.Command, args []string) error {
|
||||
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
|
||||
if o.client, err = o.Factory.KubernetesClientSet(); err != nil {
|
||||
if o.client, err = f.KubernetesClientSet(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -236,21 +256,35 @@ func (o *DrainOptions) SetupDrain(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
o.restClient, err = o.Factory.RESTClient()
|
||||
o.restClient, err = f.RESTClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.nodeInfos = []*resource.Info{}
|
||||
|
||||
cmdNamespace, _, err := o.Factory.DefaultNamespace()
|
||||
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
builder := o.Factory.NewBuilder().
|
||||
Internal().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
o.ToPrinter = func(operation string) (printers.ResourcePrinterFunc, error) {
|
||||
o.PrintFlags.NamePrintFlags.Operation = operation
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return printer.PrintObj, nil
|
||||
}
|
||||
|
||||
builder := f.NewBuilder().
|
||||
WithScheme(legacyscheme.Scheme).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
ResourceNames("nodes", args...).
|
||||
SingleResourceType().
|
||||
Flatten()
|
||||
@ -270,7 +304,7 @@ func (o *DrainOptions) SetupDrain(cmd *cobra.Command, args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.Mapping.Resource != "nodes" {
|
||||
if info.Mapping.Resource.GroupResource() != (schema.GroupResource{Group: "", Resource: "nodes"}) {
|
||||
return fmt.Errorf("error: expected resource of type node, got %q", info.Mapping.Resource)
|
||||
}
|
||||
|
||||
@ -285,6 +319,11 @@ func (o *DrainOptions) RunDrain() error {
|
||||
return err
|
||||
}
|
||||
|
||||
printObj, err := o.ToPrinter("drained")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
drainedNodes := sets.NewString()
|
||||
var fatal error
|
||||
|
||||
@ -295,7 +334,7 @@ func (o *DrainOptions) RunDrain() error {
|
||||
}
|
||||
if err == nil || o.DryRun {
|
||||
drainedNodes.Insert(info.Name)
|
||||
cmdutil.PrintSuccess(false, o.Out, info.Object, o.DryRun, "drained")
|
||||
printObj(info.Object, o.Out)
|
||||
} else {
|
||||
fmt.Fprintf(o.ErrOut, "error: unable to drain node %q, aborting command...\n\n", info.Name)
|
||||
remainingNodes := []string{}
|
||||
@ -554,7 +593,7 @@ func (o *DrainOptions) evictPods(pods []corev1.Pod, policyGroupVersion string, g
|
||||
}
|
||||
}
|
||||
podArray := []corev1.Pod{pod}
|
||||
_, err = o.waitForDelete(podArray, kubectl.Interval, time.Duration(math.MaxInt64), true, getPodFn)
|
||||
_, err = o.waitForDelete(podArray, 1*time.Second, time.Duration(math.MaxInt64), true, getPodFn)
|
||||
if err == nil {
|
||||
doneCh <- true
|
||||
} else {
|
||||
@ -600,7 +639,7 @@ func (o *DrainOptions) deletePods(pods []corev1.Pod, getPodFn func(namespace, na
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err := o.waitForDelete(pods, kubectl.Interval, globalTimeout, false, getPodFn)
|
||||
_, err := o.waitForDelete(pods, 1*time.Second, globalTimeout, false, getPodFn)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -611,12 +650,17 @@ func (o *DrainOptions) waitForDelete(pods []corev1.Pod, interval, timeout time.D
|
||||
} else {
|
||||
verbStr = "deleted"
|
||||
}
|
||||
err := wait.PollImmediate(interval, timeout, func() (bool, error) {
|
||||
printObj, err := o.ToPrinter(verbStr)
|
||||
if err != nil {
|
||||
return pods, err
|
||||
}
|
||||
|
||||
err = wait.PollImmediate(interval, timeout, func() (bool, error) {
|
||||
pendingPods := []corev1.Pod{}
|
||||
for i, pod := range pods {
|
||||
p, err := getPodFn(pod.Namespace, pod.Name)
|
||||
if apierrors.IsNotFound(err) || (p != nil && p.ObjectMeta.UID != pod.ObjectMeta.UID) {
|
||||
cmdutil.PrintSuccess(false, o.Out, &pod, false, verbStr)
|
||||
printObj(&pod, o.Out)
|
||||
continue
|
||||
} else if err != nil {
|
||||
return false, err
|
||||
@ -668,11 +712,6 @@ func SupportEviction(clientset kubernetes.Interface) (string, error) {
|
||||
// RunCordonOrUncordon runs either Cordon or Uncordon. The desired value for
|
||||
// "Unschedulable" is passed as the first arg.
|
||||
func (o *DrainOptions) RunCordonOrUncordon(desired bool) error {
|
||||
cmdNamespace, _, err := o.Factory.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cordonOrUncordon := "cordon"
|
||||
if !desired {
|
||||
cordonOrUncordon = "un" + cordonOrUncordon
|
||||
@ -680,7 +719,7 @@ func (o *DrainOptions) RunCordonOrUncordon(desired bool) error {
|
||||
|
||||
for _, nodeInfo := range o.nodeInfos {
|
||||
if nodeInfo.Mapping.GroupVersionKind.Kind == "Node" {
|
||||
obj, err := nodeInfo.Mapping.ConvertToVersion(nodeInfo.Object, nodeInfo.Mapping.GroupVersionKind.GroupVersion())
|
||||
obj, err := legacyscheme.Scheme.ConvertToVersion(nodeInfo.Object, nodeInfo.Mapping.GroupVersionKind.GroupVersion())
|
||||
if err != nil {
|
||||
fmt.Printf("error: unable to %s node %q: %v", cordonOrUncordon, nodeInfo.Name, err)
|
||||
continue
|
||||
@ -697,7 +736,12 @@ func (o *DrainOptions) RunCordonOrUncordon(desired bool) error {
|
||||
}
|
||||
unsched := node.Spec.Unschedulable
|
||||
if unsched == desired {
|
||||
cmdutil.PrintSuccess(false, o.Out, nodeInfo.Object, o.DryRun, already(desired))
|
||||
printObj, err := o.ToPrinter(already(desired))
|
||||
if err != nil {
|
||||
fmt.Printf("error: %v", err)
|
||||
continue
|
||||
}
|
||||
printObj(cmdutil.AsDefaultVersionedOrOriginal(nodeInfo.Object, nodeInfo.Mapping), o.Out)
|
||||
} else {
|
||||
if !o.DryRun {
|
||||
helper := resource.NewHelper(o.restClient, nodeInfo.Mapping)
|
||||
@ -712,16 +756,26 @@ func (o *DrainOptions) RunCordonOrUncordon(desired bool) error {
|
||||
fmt.Printf("error: unable to %s node %q: %v", cordonOrUncordon, nodeInfo.Name, err)
|
||||
continue
|
||||
}
|
||||
_, err = helper.Patch(cmdNamespace, nodeInfo.Name, types.StrategicMergePatchType, patchBytes)
|
||||
_, err = helper.Patch(o.Namespace, nodeInfo.Name, types.StrategicMergePatchType, patchBytes)
|
||||
if err != nil {
|
||||
fmt.Printf("error: unable to %s node %q: %v", cordonOrUncordon, nodeInfo.Name, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
cmdutil.PrintSuccess(false, o.Out, nodeInfo.Object, o.DryRun, changed(desired))
|
||||
printObj, err := o.ToPrinter(changed(desired))
|
||||
if err != nil {
|
||||
fmt.Fprintf(o.ErrOut, "%v", err)
|
||||
continue
|
||||
}
|
||||
printObj(cmdutil.AsDefaultVersionedOrOriginal(nodeInfo.Object, nodeInfo.Mapping), o.Out)
|
||||
}
|
||||
} else {
|
||||
cmdutil.PrintSuccess(false, o.Out, nodeInfo.Object, o.DryRun, "skipped")
|
||||
printObj, err := o.ToPrinter("skipped")
|
||||
if err != nil {
|
||||
fmt.Fprintf(o.ErrOut, "%v", err)
|
||||
continue
|
||||
}
|
||||
printObj(cmdutil.AsDefaultVersionedOrOriginal(nodeInfo.Object, nodeInfo.Mapping), o.Out)
|
||||
}
|
||||
}
|
||||
|
||||
|
509
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/drain_test.go
generated
vendored
509
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/drain_test.go
generated
vendored
@ -17,7 +17,6 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -32,6 +31,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
policyv1beta1 "k8s.io/api/policy/v1beta1"
|
||||
@ -50,6 +50,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
@ -70,9 +71,6 @@ func TestMain(m *testing.M) {
|
||||
Name: "node",
|
||||
CreationTimestamp: metav1.Time{Time: time.Now()},
|
||||
},
|
||||
Spec: corev1.NodeSpec{
|
||||
ExternalID: "node",
|
||||
},
|
||||
Status: corev1.NodeStatus{},
|
||||
}
|
||||
|
||||
@ -87,7 +85,7 @@ func TestCordon(t *testing.T) {
|
||||
description string
|
||||
node *corev1.Node
|
||||
expected *corev1.Node
|
||||
cmd func(cmdutil.Factory, io.Writer) *cobra.Command
|
||||
cmd func(cmdutil.Factory, genericclioptions.IOStreams) *cobra.Command
|
||||
arg string
|
||||
expectFatal bool
|
||||
}{
|
||||
@ -150,86 +148,90 @@ func TestCordon(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
ns := legacyscheme.Codecs
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
|
||||
new_node := &corev1.Node{}
|
||||
updated := false
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
m := &MyReq{req}
|
||||
switch {
|
||||
case m.isFor("GET", "/nodes/node"):
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, test.node)}, nil
|
||||
case m.isFor("GET", "/nodes/bar"):
|
||||
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: stringBody("nope")}, nil
|
||||
case m.isFor("PATCH", "/nodes/node"):
|
||||
data, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
defer req.Body.Close()
|
||||
oldJSON, err := runtime.Encode(codec, node)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
appliedPatch, err := strategicpatch.StrategicMergePatch(oldJSON, data, &corev1.Node{})
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
if err := runtime.DecodeInto(codec, appliedPatch, new_node); err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
if !reflect.DeepEqual(test.expected.Spec, new_node.Spec) {
|
||||
t.Fatalf("%s: expected:\n%v\nsaw:\n%v\n", test.description, test.expected.Spec.Unschedulable, new_node.Spec.Unschedulable)
|
||||
}
|
||||
updated = true
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, new_node)}, nil
|
||||
default:
|
||||
t.Fatalf("%s: unexpected request: %v %#v\n%#v", test.description, req.Method, req.URL, req)
|
||||
return nil, nil
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := test.cmd(tf, buf)
|
||||
new_node := &corev1.Node{}
|
||||
updated := false
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
m := &MyReq{req}
|
||||
switch {
|
||||
case m.isFor("GET", "/nodes/node"):
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, test.node)}, nil
|
||||
case m.isFor("GET", "/nodes/bar"):
|
||||
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: stringBody("nope")}, nil
|
||||
case m.isFor("PATCH", "/nodes/node"):
|
||||
data, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
defer req.Body.Close()
|
||||
oldJSON, err := runtime.Encode(codec, node)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
appliedPatch, err := strategicpatch.StrategicMergePatch(oldJSON, data, &corev1.Node{})
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
if err := runtime.DecodeInto(codec, appliedPatch, new_node); err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
if !reflect.DeepEqual(test.expected.Spec, new_node.Spec) {
|
||||
t.Fatalf("%s: expected:\n%v\nsaw:\n%v\n", test.description, test.expected.Spec.Unschedulable, new_node.Spec.Unschedulable)
|
||||
}
|
||||
updated = true
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, new_node)}, nil
|
||||
default:
|
||||
t.Fatalf("%s: unexpected request: %v %#v\n%#v", test.description, req.Method, req.URL, req)
|
||||
return nil, nil
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
saw_fatal := false
|
||||
func() {
|
||||
defer func() {
|
||||
// Recover from the panic below.
|
||||
_ = recover()
|
||||
// Restore cmdutil behavior
|
||||
cmdutil.DefaultBehaviorOnFatal()
|
||||
ioStreams, _, _, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := test.cmd(tf, ioStreams)
|
||||
|
||||
saw_fatal := false
|
||||
func() {
|
||||
defer func() {
|
||||
// Recover from the panic below.
|
||||
_ = recover()
|
||||
// Restore cmdutil behavior
|
||||
cmdutil.DefaultBehaviorOnFatal()
|
||||
}()
|
||||
cmdutil.BehaviorOnFatal(func(e string, code int) {
|
||||
saw_fatal = true
|
||||
panic(e)
|
||||
})
|
||||
cmd.SetArgs([]string{test.arg})
|
||||
cmd.Execute()
|
||||
}()
|
||||
cmdutil.BehaviorOnFatal(func(e string, code int) {
|
||||
saw_fatal = true
|
||||
panic(e)
|
||||
})
|
||||
cmd.SetArgs([]string{test.arg})
|
||||
cmd.Execute()
|
||||
}()
|
||||
|
||||
if test.expectFatal {
|
||||
if !saw_fatal {
|
||||
t.Fatalf("%s: unexpected non-error", test.description)
|
||||
if test.expectFatal {
|
||||
if !saw_fatal {
|
||||
t.Fatalf("%s: unexpected non-error", test.description)
|
||||
}
|
||||
if updated {
|
||||
t.Fatalf("%s: unexpected update", test.description)
|
||||
}
|
||||
}
|
||||
if updated {
|
||||
t.Fatalf("%s: unexpected update", test.description)
|
||||
}
|
||||
}
|
||||
|
||||
if !test.expectFatal && saw_fatal {
|
||||
t.Fatalf("%s: unexpected error", test.description)
|
||||
}
|
||||
if !reflect.DeepEqual(test.expected.Spec, test.node.Spec) && !updated {
|
||||
t.Fatalf("%s: node never updated", test.description)
|
||||
}
|
||||
if !test.expectFatal && saw_fatal {
|
||||
t.Fatalf("%s: unexpected error", test.description)
|
||||
}
|
||||
if !reflect.DeepEqual(test.expected.Spec, test.node.Spec) && !updated {
|
||||
t.Fatalf("%s: node never updated", test.description)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -597,164 +599,167 @@ func TestDrain(t *testing.T) {
|
||||
currMethod = DeleteMethod
|
||||
}
|
||||
for _, test := range tests {
|
||||
new_node := &corev1.Node{}
|
||||
deleted := false
|
||||
evicted := false
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
ns := legacyscheme.Codecs
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
new_node := &corev1.Node{}
|
||||
deleted := false
|
||||
evicted := false
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
m := &MyReq{req}
|
||||
switch {
|
||||
case req.Method == "GET" && req.URL.Path == "/api":
|
||||
apiVersions := metav1.APIVersions{
|
||||
Versions: []string{"v1"},
|
||||
}
|
||||
return genResponseWithJsonEncodedBody(apiVersions)
|
||||
case req.Method == "GET" && req.URL.Path == "/apis":
|
||||
groupList := metav1.APIGroupList{
|
||||
Groups: []metav1.APIGroup{
|
||||
{
|
||||
Name: "policy",
|
||||
PreferredVersion: metav1.GroupVersionForDiscovery{
|
||||
GroupVersion: "policy/v1beta1",
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
m := &MyReq{req}
|
||||
switch {
|
||||
case req.Method == "GET" && req.URL.Path == "/api":
|
||||
apiVersions := metav1.APIVersions{
|
||||
Versions: []string{"v1"},
|
||||
}
|
||||
return genResponseWithJsonEncodedBody(apiVersions)
|
||||
case req.Method == "GET" && req.URL.Path == "/apis":
|
||||
groupList := metav1.APIGroupList{
|
||||
Groups: []metav1.APIGroup{
|
||||
{
|
||||
Name: "policy",
|
||||
PreferredVersion: metav1.GroupVersionForDiscovery{
|
||||
GroupVersion: "policy/v1beta1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return genResponseWithJsonEncodedBody(groupList)
|
||||
case req.Method == "GET" && req.URL.Path == "/api/v1":
|
||||
resourceList := metav1.APIResourceList{
|
||||
GroupVersion: "v1",
|
||||
}
|
||||
if testEviction {
|
||||
resourceList.APIResources = []metav1.APIResource{
|
||||
{
|
||||
Name: EvictionSubresource,
|
||||
Kind: EvictionKind,
|
||||
},
|
||||
}
|
||||
return genResponseWithJsonEncodedBody(groupList)
|
||||
case req.Method == "GET" && req.URL.Path == "/api/v1":
|
||||
resourceList := metav1.APIResourceList{
|
||||
GroupVersion: "v1",
|
||||
}
|
||||
if testEviction {
|
||||
resourceList.APIResources = []metav1.APIResource{
|
||||
{
|
||||
Name: EvictionSubresource,
|
||||
Kind: EvictionKind,
|
||||
},
|
||||
}
|
||||
}
|
||||
return genResponseWithJsonEncodedBody(resourceList)
|
||||
case m.isFor("GET", "/nodes/node"):
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, test.node)}, nil
|
||||
case m.isFor("GET", "/namespaces/default/replicationcontrollers/rc"):
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &test.rcs[0])}, nil
|
||||
case m.isFor("GET", "/namespaces/default/daemonsets/ds"):
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(testapi.Extensions.Codec(), &ds)}, nil
|
||||
case m.isFor("GET", "/namespaces/default/daemonsets/missing-ds"):
|
||||
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: objBody(testapi.Extensions.Codec(), &extensions.DaemonSet{})}, nil
|
||||
case m.isFor("GET", "/namespaces/default/jobs/job"):
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(testapi.Batch.Codec(), &job)}, nil
|
||||
case m.isFor("GET", "/namespaces/default/replicasets/rs"):
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(testapi.Extensions.Codec(), &test.replicaSets[0])}, nil
|
||||
case m.isFor("GET", "/namespaces/default/pods/bar"):
|
||||
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: objBody(codec, &corev1.Pod{})}, nil
|
||||
case m.isFor("GET", "/pods"):
|
||||
values, err := url.ParseQuery(req.URL.RawQuery)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
get_params := make(url.Values)
|
||||
get_params["fieldSelector"] = []string{"spec.nodeName=node"}
|
||||
if !reflect.DeepEqual(get_params, values) {
|
||||
t.Fatalf("%s: expected:\n%v\nsaw:\n%v\n", test.description, get_params, values)
|
||||
}
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &corev1.PodList{Items: test.pods})}, nil
|
||||
case m.isFor("GET", "/replicationcontrollers"):
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &api.ReplicationControllerList{Items: test.rcs})}, nil
|
||||
case m.isFor("PATCH", "/nodes/node"):
|
||||
data, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
defer req.Body.Close()
|
||||
oldJSON, err := runtime.Encode(codec, node)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
appliedPatch, err := strategicpatch.StrategicMergePatch(oldJSON, data, &corev1.Node{})
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
if err := runtime.DecodeInto(codec, appliedPatch, new_node); err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
if !reflect.DeepEqual(test.expected.Spec, new_node.Spec) {
|
||||
t.Fatalf("%s: expected:\n%v\nsaw:\n%v\n", test.description, test.expected.Spec, new_node.Spec)
|
||||
}
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, new_node)}, nil
|
||||
case m.isFor("DELETE", "/namespaces/default/pods/bar"):
|
||||
deleted = true
|
||||
return &http.Response{StatusCode: 204, Header: defaultHeader(), Body: objBody(codec, &test.pods[0])}, nil
|
||||
case m.isFor("POST", "/namespaces/default/pods/bar/eviction"):
|
||||
evicted = true
|
||||
return &http.Response{StatusCode: 201, Header: defaultHeader(), Body: policyObjBody(&policyv1beta1.Eviction{})}, nil
|
||||
default:
|
||||
t.Fatalf("%s: unexpected request: %v %#v\n%#v", test.description, req.Method, req.URL, req)
|
||||
return nil, nil
|
||||
}
|
||||
return genResponseWithJsonEncodedBody(resourceList)
|
||||
case m.isFor("GET", "/nodes/node"):
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, test.node)}, nil
|
||||
case m.isFor("GET", "/namespaces/default/replicationcontrollers/rc"):
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &test.rcs[0])}, nil
|
||||
case m.isFor("GET", "/namespaces/default/daemonsets/ds"):
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(testapi.Extensions.Codec(), &ds)}, nil
|
||||
case m.isFor("GET", "/namespaces/default/daemonsets/missing-ds"):
|
||||
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: objBody(testapi.Extensions.Codec(), &extensions.DaemonSet{})}, nil
|
||||
case m.isFor("GET", "/namespaces/default/jobs/job"):
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(testapi.Batch.Codec(), &job)}, nil
|
||||
case m.isFor("GET", "/namespaces/default/replicasets/rs"):
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(testapi.Extensions.Codec(), &test.replicaSets[0])}, nil
|
||||
case m.isFor("GET", "/namespaces/default/pods/bar"):
|
||||
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: objBody(codec, &corev1.Pod{})}, nil
|
||||
case m.isFor("GET", "/pods"):
|
||||
values, err := url.ParseQuery(req.URL.RawQuery)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
get_params := make(url.Values)
|
||||
get_params["fieldSelector"] = []string{"spec.nodeName=node"}
|
||||
if !reflect.DeepEqual(get_params, values) {
|
||||
t.Fatalf("%s: expected:\n%v\nsaw:\n%v\n", test.description, get_params, values)
|
||||
}
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &corev1.PodList{Items: test.pods})}, nil
|
||||
case m.isFor("GET", "/replicationcontrollers"):
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &api.ReplicationControllerList{Items: test.rcs})}, nil
|
||||
case m.isFor("PATCH", "/nodes/node"):
|
||||
data, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
defer req.Body.Close()
|
||||
oldJSON, err := runtime.Encode(codec, node)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
appliedPatch, err := strategicpatch.StrategicMergePatch(oldJSON, data, &corev1.Node{})
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
if err := runtime.DecodeInto(codec, appliedPatch, new_node); err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", test.description, err)
|
||||
}
|
||||
if !reflect.DeepEqual(test.expected.Spec, new_node.Spec) {
|
||||
t.Fatalf("%s: expected:\n%v\nsaw:\n%v\n", test.description, test.expected.Spec, new_node.Spec)
|
||||
}
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, new_node)}, nil
|
||||
case m.isFor("DELETE", "/namespaces/default/pods/bar"):
|
||||
deleted = true
|
||||
return &http.Response{StatusCode: 204, Header: defaultHeader(), Body: objBody(codec, &test.pods[0])}, nil
|
||||
case m.isFor("POST", "/namespaces/default/pods/bar/eviction"):
|
||||
evicted = true
|
||||
return &http.Response{StatusCode: 201, Header: defaultHeader(), Body: policyObjBody(&policyv1beta1.Eviction{})}, nil
|
||||
default:
|
||||
t.Fatalf("%s: unexpected request: %v %#v\n%#v", test.description, req.Method, req.URL, req)
|
||||
return nil, nil
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdDrain(tf, buf, errBuf)
|
||||
ioStreams, _, _, errBuf := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdDrain(tf, ioStreams)
|
||||
|
||||
saw_fatal := false
|
||||
fatal_msg := ""
|
||||
func() {
|
||||
defer func() {
|
||||
// Recover from the panic below.
|
||||
_ = recover()
|
||||
// Restore cmdutil behavior
|
||||
cmdutil.DefaultBehaviorOnFatal()
|
||||
saw_fatal := false
|
||||
fatal_msg := ""
|
||||
func() {
|
||||
defer func() {
|
||||
// Recover from the panic below.
|
||||
_ = recover()
|
||||
// Restore cmdutil behavior
|
||||
cmdutil.DefaultBehaviorOnFatal()
|
||||
}()
|
||||
cmdutil.BehaviorOnFatal(func(e string, code int) { saw_fatal = true; fatal_msg = e; panic(e) })
|
||||
cmd.SetArgs(test.args)
|
||||
cmd.Execute()
|
||||
}()
|
||||
cmdutil.BehaviorOnFatal(func(e string, code int) { saw_fatal = true; fatal_msg = e; panic(e) })
|
||||
cmd.SetArgs(test.args)
|
||||
cmd.Execute()
|
||||
}()
|
||||
if test.expectFatal {
|
||||
if !saw_fatal {
|
||||
t.Fatalf("%s: unexpected non-error when using %s", test.description, currMethod)
|
||||
}
|
||||
} else {
|
||||
if saw_fatal {
|
||||
t.Fatalf("%s: unexpected error when using %s: %s", test.description, currMethod, fatal_msg)
|
||||
if test.expectFatal {
|
||||
if !saw_fatal {
|
||||
t.Fatalf("%s: unexpected non-error when using %s", test.description, currMethod)
|
||||
}
|
||||
} else {
|
||||
if saw_fatal {
|
||||
t.Fatalf("%s: unexpected error when using %s: %s", test.description, currMethod, fatal_msg)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if test.expectDelete {
|
||||
// Test Delete
|
||||
if !testEviction && !deleted {
|
||||
t.Fatalf("%s: pod never deleted", test.description)
|
||||
}
|
||||
// Test Eviction
|
||||
if testEviction && !evicted {
|
||||
t.Fatalf("%s: pod never evicted", test.description)
|
||||
}
|
||||
}
|
||||
if !test.expectDelete {
|
||||
if deleted {
|
||||
t.Fatalf("%s: unexpected delete when using %s", test.description, currMethod)
|
||||
}
|
||||
}
|
||||
|
||||
if len(test.expectWarning) > 0 {
|
||||
if len(errBuf.String()) == 0 {
|
||||
t.Fatalf("%s: expected warning, but found no stderr output", test.description)
|
||||
}
|
||||
}
|
||||
|
||||
if errBuf.String() != test.expectWarning {
|
||||
t.Fatalf("%s: actual warning message did not match expected warning message.\n Expecting: %s\n Got: %s", test.description, test.expectWarning, errBuf.String())
|
||||
if test.expectDelete {
|
||||
// Test Delete
|
||||
if !testEviction && !deleted {
|
||||
t.Fatalf("%s: pod never deleted", test.description)
|
||||
}
|
||||
// Test Eviction
|
||||
if testEviction && !evicted {
|
||||
t.Fatalf("%s: pod never evicted", test.description)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !test.expectDelete {
|
||||
if deleted {
|
||||
t.Fatalf("%s: unexpected delete when using %s", test.description, currMethod)
|
||||
}
|
||||
}
|
||||
|
||||
if len(test.expectWarning) > 0 {
|
||||
if len(errBuf.String()) == 0 {
|
||||
t.Fatalf("%s: expected warning, but found no stderr output", test.description)
|
||||
}
|
||||
|
||||
if errBuf.String() != test.expectWarning {
|
||||
t.Fatalf("%s: actual warning message did not match expected warning message.\n Expecting: %s\n Got: %s", test.description, test.expectWarning, errBuf.String())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -824,31 +829,43 @@ func TestDeletePods(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
o := DrainOptions{Factory: tf}
|
||||
o.mapper, _ = tf.Object()
|
||||
o.Out = os.Stdout
|
||||
_, pods := createPods(false)
|
||||
pendingPods, err := o.waitForDelete(pods, test.interval, test.timeout, false, test.getPodFn)
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
|
||||
if test.expectError {
|
||||
if err == nil {
|
||||
t.Fatalf("%s: unexpected non-error", test.description)
|
||||
} else if test.expectedError != nil {
|
||||
if *test.expectedError != err {
|
||||
t.Fatalf("%s: the error does not match expected error", test.description)
|
||||
o := DrainOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("drained").WithTypeSetter(scheme.Scheme),
|
||||
}
|
||||
o.Out = os.Stdout
|
||||
|
||||
o.ToPrinter = func(operation string) (printers.ResourcePrinterFunc, error) {
|
||||
return func(obj runtime.Object, out io.Writer) error {
|
||||
return nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
_, pods := createPods(false)
|
||||
pendingPods, err := o.waitForDelete(pods, test.interval, test.timeout, false, test.getPodFn)
|
||||
|
||||
if test.expectError {
|
||||
if err == nil {
|
||||
t.Fatalf("%s: unexpected non-error", test.description)
|
||||
} else if test.expectedError != nil {
|
||||
if *test.expectedError != err {
|
||||
t.Fatalf("%s: the error does not match expected error", test.description)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !test.expectError && err != nil {
|
||||
t.Fatalf("%s: unexpected error", test.description)
|
||||
}
|
||||
if test.expectPendingPods && len(pendingPods) == 0 {
|
||||
t.Fatalf("%s: unexpected empty pods", test.description)
|
||||
}
|
||||
if !test.expectPendingPods && len(pendingPods) > 0 {
|
||||
t.Fatalf("%s: unexpected pending pods", test.description)
|
||||
}
|
||||
if !test.expectError && err != nil {
|
||||
t.Fatalf("%s: unexpected error", test.description)
|
||||
}
|
||||
if test.expectPendingPods && len(pendingPods) == 0 {
|
||||
t.Fatalf("%s: unexpected empty pods", test.description)
|
||||
}
|
||||
if !test.expectPendingPods && len(pendingPods) > 0 {
|
||||
t.Fatalf("%s: unexpected pending pods", test.description)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
40
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/edit.go
generated
vendored
40
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/edit.go
generated
vendored
@ -18,15 +18,13 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -69,13 +67,9 @@ var (
|
||||
kubectl edit deployment/mydeployment -o yaml --save-config`))
|
||||
)
|
||||
|
||||
func NewCmdEdit(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
options := &editor.EditOptions{
|
||||
EditMode: editor.NormalEditMode,
|
||||
ValidateOptions: cmdutil.ValidateOptions{EnableValidation: true},
|
||||
Include3rdParty: true,
|
||||
}
|
||||
validArgs := cmdutil.ValidArgList(f)
|
||||
func NewCmdEdit(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := editor.NewEditOptions(editor.NormalEditMode, ioStreams)
|
||||
o.ValidateOptions = cmdutil.ValidateOptions{EnableValidation: true}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "edit (RESOURCE/NAME | -f FILENAME)",
|
||||
@ -84,29 +78,27 @@ func NewCmdEdit(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
Long: editLong,
|
||||
Example: fmt.Sprintf(editExample),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
options.ChangeCause = f.Command(cmd, false)
|
||||
if err := options.Complete(f, out, errOut, args, cmd); err != nil {
|
||||
if err := o.Complete(f, args, cmd); err != nil {
|
||||
cmdutil.CheckErr(err)
|
||||
}
|
||||
if err := options.Run(); err != nil {
|
||||
if err := o.Run(); err != nil {
|
||||
cmdutil.CheckErr(err)
|
||||
}
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
}
|
||||
usage := "to use to edit the resource"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmdutil.AddValidateOptionFlags(cmd, &options.ValidateOptions)
|
||||
cmd.Flags().StringVarP(&options.Output, "output", "o", "yaml", "Output format. One of: yaml|json.")
|
||||
cmd.Flags().BoolVarP(&options.OutputPatch, "output-patch", "", false, "Output the patch if the resource is edited.")
|
||||
|
||||
cmd.Flags().BoolVar(&options.WindowsLineEndings, "windows-line-endings", runtime.GOOS == "windows",
|
||||
// bind flag structs
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
usage := "to use to edit the resource"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||
cmdutil.AddValidateOptionFlags(cmd, &o.ValidateOptions)
|
||||
cmd.Flags().BoolVarP(&o.OutputPatch, "output-patch", "", o.OutputPatch, "Output the patch if the resource is edited.")
|
||||
cmd.Flags().BoolVar(&o.WindowsLineEndings, "windows-line-endings", o.WindowsLineEndings,
|
||||
"Defaults to the line ending native to your platform.")
|
||||
|
||||
cmdutil.AddApplyAnnotationVarFlags(cmd, &options.ApplyAnnotation)
|
||||
cmdutil.AddRecordVarFlag(cmd, &options.Record)
|
||||
cmdutil.AddInclude3rdPartyVarFlags(cmd, &options.Include3rdParty)
|
||||
cmdutil.AddApplyAnnotationVarFlags(cmd, &o.ApplyAnnotation)
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
31
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/edit_test.go
generated
vendored
31
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/edit_test.go
generated
vendored
@ -32,13 +32,15 @@ import (
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/create"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
)
|
||||
|
||||
type EditTestCase struct {
|
||||
@ -207,12 +209,14 @@ func TestEdit(t *testing.T) {
|
||||
}
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.UnstructuredClientForMappingFunc = func(mapping *meta.RESTMapping) (resource.RESTClient, error) {
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.UnstructuredClientForMappingFunc = func(gv schema.GroupVersion) (resource.RESTClient, error) {
|
||||
versionedAPIPath := ""
|
||||
if mapping.GroupVersionKind.Group == "" {
|
||||
versionedAPIPath = "/api/" + mapping.GroupVersionKind.Version
|
||||
if gv.Group == "" {
|
||||
versionedAPIPath = "/api/" + gv.Version
|
||||
} else {
|
||||
versionedAPIPath = "/apis/" + mapping.GroupVersionKind.Group + "/" + mapping.GroupVersionKind.Version
|
||||
versionedAPIPath = "/apis/" + gv.Group + "/" + gv.Version
|
||||
}
|
||||
return &fake.RESTClient{
|
||||
VersionedAPIPath: versionedAPIPath,
|
||||
@ -220,24 +224,19 @@ func TestEdit(t *testing.T) {
|
||||
Client: fake.CreateHTTPClient(reqResp),
|
||||
}, nil
|
||||
}
|
||||
|
||||
if len(testcase.Namespace) > 0 {
|
||||
tf.Namespace = testcase.Namespace
|
||||
}
|
||||
tf.WithNamespace(testcase.Namespace)
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
tf.CommandVal = "edit test cmd invocation"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams()
|
||||
|
||||
var cmd *cobra.Command
|
||||
switch testcase.Mode {
|
||||
case "edit":
|
||||
cmd = NewCmdEdit(tf, buf, errBuf)
|
||||
cmd = NewCmdEdit(tf, ioStreams)
|
||||
case "create":
|
||||
cmd = NewCmdCreate(tf, buf, errBuf)
|
||||
cmd = create.NewCmdCreate(tf, ioStreams)
|
||||
cmd.Flags().Set("edit", "true")
|
||||
case "edit-last-applied":
|
||||
cmd = NewCmdApplyEditLastApplied(tf, buf, errBuf)
|
||||
cmd = NewCmdApplyEditLastApplied(tf, ioStreams)
|
||||
default:
|
||||
t.Fatalf("%s: unexpected mode %s", name, testcase.Mode)
|
||||
}
|
||||
|
40
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/exec.go
generated
vendored
40
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/exec.go
generated
vendored
@ -32,6 +32,7 @@ import (
|
||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/term"
|
||||
"k8s.io/kubernetes/pkg/util/interrupt"
|
||||
@ -62,12 +63,10 @@ const (
|
||||
execUsageStr = "expected 'exec POD_NAME COMMAND [ARG1] [ARG2] ... [ARGN]'.\nPOD_NAME and COMMAND are required arguments for the exec command"
|
||||
)
|
||||
|
||||
func NewCmdExec(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command {
|
||||
func NewCmdExec(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := &ExecOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
In: cmdIn,
|
||||
Out: cmdOut,
|
||||
Err: cmdErr,
|
||||
IOStreams: streams,
|
||||
},
|
||||
|
||||
Executor: &DefaultRemoteExecutor{},
|
||||
@ -85,11 +84,11 @@ func NewCmdExec(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *c
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringVarP(&options.PodName, "pod", "p", "", "Pod name")
|
||||
cmd.Flags().StringVarP(&options.PodName, "pod", "p", options.PodName, "Pod name")
|
||||
// TODO support UID
|
||||
cmd.Flags().StringVarP(&options.ContainerName, "container", "c", "", "Container name. If omitted, the first container in the pod will be chosen")
|
||||
cmd.Flags().BoolVarP(&options.Stdin, "stdin", "i", false, "Pass stdin to the container")
|
||||
cmd.Flags().BoolVarP(&options.TTY, "tty", "t", false, "Stdin is a TTY")
|
||||
cmd.Flags().StringVarP(&options.ContainerName, "container", "c", options.ContainerName, "Container name. If omitted, the first container in the pod will be chosen")
|
||||
cmd.Flags().BoolVarP(&options.Stdin, "stdin", "i", options.Stdin, "Pass stdin to the container")
|
||||
cmd.Flags().BoolVarP(&options.TTY, "tty", "t", options.TTY, "Stdin is a TTY")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -125,9 +124,8 @@ type StreamOptions struct {
|
||||
Quiet bool
|
||||
// InterruptParent, if set, is used to handle interrupts while attached
|
||||
InterruptParent *interrupt.Handler
|
||||
In io.Reader
|
||||
Out io.Writer
|
||||
Err io.Writer
|
||||
|
||||
genericclioptions.IOStreams
|
||||
|
||||
// for testing
|
||||
overrideStreams func() (io.ReadCloser, io.Writer, io.Writer)
|
||||
@ -155,7 +153,7 @@ func (p *ExecOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn []s
|
||||
return cmdutil.UsageErrorf(cmd, execUsageStr)
|
||||
}
|
||||
if len(p.PodName) != 0 {
|
||||
printDeprecationWarning(p.Err, "exec POD_NAME", "-p POD_NAME")
|
||||
printDeprecationWarning(p.ErrOut, "exec POD_NAME", "-p POD_NAME")
|
||||
if len(argsIn) < 1 {
|
||||
return cmdutil.UsageErrorf(cmd, execUsageStr)
|
||||
}
|
||||
@ -168,7 +166,7 @@ func (p *ExecOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn []s
|
||||
}
|
||||
}
|
||||
|
||||
namespace, _, err := f.DefaultNamespace()
|
||||
namespace, _, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -182,7 +180,7 @@ func (p *ExecOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn []s
|
||||
p.SuggestedCmdUsage = fmt.Sprintf("Use '%s describe pod/%s -n %s' to see all of the containers in this pod.", p.FullCmdName, p.PodName, p.Namespace)
|
||||
}
|
||||
|
||||
config, err := f.ClientConfig()
|
||||
config, err := f.ToRESTConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -205,7 +203,7 @@ func (p *ExecOptions) Validate() error {
|
||||
if len(p.Command) == 0 {
|
||||
return fmt.Errorf("you must specify at least one command for the container")
|
||||
}
|
||||
if p.Out == nil || p.Err == nil {
|
||||
if p.Out == nil || p.ErrOut == nil {
|
||||
return fmt.Errorf("both output and error output must be provided")
|
||||
}
|
||||
if p.Executor == nil || p.PodClient == nil || p.Config == nil {
|
||||
@ -240,8 +238,8 @@ func (o *StreamOptions) setupTTY() term.TTY {
|
||||
if !o.isTerminalIn(t) {
|
||||
o.TTY = false
|
||||
|
||||
if o.Err != nil {
|
||||
fmt.Fprintln(o.Err, "Unable to use a TTY - input is not a terminal or the right kind of file")
|
||||
if o.ErrOut != nil {
|
||||
fmt.Fprintln(o.ErrOut, "Unable to use a TTY - input is not a terminal or the right kind of file")
|
||||
}
|
||||
|
||||
return t
|
||||
@ -284,7 +282,7 @@ func (p *ExecOptions) Run() error {
|
||||
if len(p.SuggestedCmdUsage) > 0 {
|
||||
usageString = fmt.Sprintf("%s\n%s", usageString, p.SuggestedCmdUsage)
|
||||
}
|
||||
fmt.Fprintf(p.Err, "%s\n", usageString)
|
||||
fmt.Fprintf(p.ErrOut, "%s\n", usageString)
|
||||
}
|
||||
containerName = pod.Spec.Containers[0].Name
|
||||
}
|
||||
@ -299,7 +297,7 @@ func (p *ExecOptions) Run() error {
|
||||
|
||||
// unset p.Err if it was previously set because both stdout and stderr go over p.Out when tty is
|
||||
// true
|
||||
p.Err = nil
|
||||
p.ErrOut = nil
|
||||
}
|
||||
|
||||
fn := func() error {
|
||||
@ -320,11 +318,11 @@ func (p *ExecOptions) Run() error {
|
||||
Command: p.Command,
|
||||
Stdin: p.Stdin,
|
||||
Stdout: p.Out != nil,
|
||||
Stderr: p.Err != nil,
|
||||
Stderr: p.ErrOut != nil,
|
||||
TTY: t.Raw,
|
||||
}, legacyscheme.ParameterCodec)
|
||||
|
||||
return p.Executor.Execute("POST", req.URL(), p.Config, p.In, p.Out, p.Err, t.Raw, sizeQueue)
|
||||
return p.Executor.Execute("POST", req.URL(), p.Config, p.In, p.Out, p.ErrOut, t.Raw, sizeQueue)
|
||||
}
|
||||
|
||||
if err := t.Safe(fn); err != nil {
|
||||
|
193
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/exec_test.go
generated
vendored
193
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/exec_test.go
generated
vendored
@ -36,6 +36,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/term"
|
||||
)
|
||||
@ -130,38 +131,41 @@ func TestPodAndContainer(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
ns := legacyscheme.Codecs
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { return nil, nil }),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
cmd := &cobra.Command{}
|
||||
options := test.p
|
||||
options.Err = bytes.NewBuffer([]byte{})
|
||||
err := options.Complete(tf, cmd, test.args, test.argsLenAtDash)
|
||||
if test.expectError && err == nil {
|
||||
t.Errorf("%s: unexpected non-error", test.name)
|
||||
}
|
||||
if !test.expectError && err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", test.name, err)
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if options.PodName != test.expectedPod {
|
||||
t.Errorf("%s: expected: %s, got: %s", test.name, test.expectedPod, options.PodName)
|
||||
}
|
||||
if options.ContainerName != test.expectedContainer {
|
||||
t.Errorf("%s: expected: %s, got: %s", test.name, test.expectedContainer, options.ContainerName)
|
||||
}
|
||||
if !reflect.DeepEqual(test.expectedArgs, options.Command) {
|
||||
t.Errorf("%s: expected: %v, got %v", test.name, test.expectedArgs, options.Command)
|
||||
}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { return nil, nil }),
|
||||
}
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
cmd := &cobra.Command{}
|
||||
options := test.p
|
||||
options.ErrOut = bytes.NewBuffer([]byte{})
|
||||
err := options.Complete(tf, cmd, test.args, test.argsLenAtDash)
|
||||
if test.expectError && err == nil {
|
||||
t.Errorf("%s: unexpected non-error", test.name)
|
||||
}
|
||||
if !test.expectError && err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", test.name, err)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if options.PodName != test.expectedPod {
|
||||
t.Errorf("%s: expected: %s, got: %s", test.name, test.expectedPod, options.PodName)
|
||||
}
|
||||
if options.ContainerName != test.expectedContainer {
|
||||
t.Errorf("%s: expected: %s, got: %s", test.name, test.expectedContainer, options.ContainerName)
|
||||
}
|
||||
if !reflect.DeepEqual(test.expectedArgs, options.Command) {
|
||||
t.Errorf("%s: expected: %v, got %v", test.name, test.expectedArgs, options.Command)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,67 +191,64 @@ func TestExec(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
ns := legacyscheme.Codecs
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == test.podPath && m == "GET":
|
||||
body := objBody(codec, test.pod)
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
default:
|
||||
// Ensures no GET is performed when deleting by name
|
||||
t.Errorf("%s: unexpected request: %s %#v\n%#v", test.name, req.Method, req.URL, req)
|
||||
return nil, fmt.Errorf("unexpected request")
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
bufOut := bytes.NewBuffer([]byte{})
|
||||
bufErr := bytes.NewBuffer([]byte{})
|
||||
bufIn := bytes.NewBuffer([]byte{})
|
||||
ex := &fakeRemoteExecutor{}
|
||||
if test.execErr {
|
||||
ex.execErr = fmt.Errorf("exec error")
|
||||
}
|
||||
params := &ExecOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
PodName: "foo",
|
||||
ContainerName: "bar",
|
||||
In: bufIn,
|
||||
Out: bufOut,
|
||||
Err: bufErr,
|
||||
},
|
||||
Executor: ex,
|
||||
}
|
||||
cmd := &cobra.Command{}
|
||||
args := []string{"test", "command"}
|
||||
if err := params.Complete(tf, cmd, args, -1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err := params.Run()
|
||||
if test.execErr && err != ex.execErr {
|
||||
t.Errorf("%s: Unexpected exec error: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
if !test.execErr && err != nil {
|
||||
t.Errorf("%s: Unexpected error: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
if test.execErr {
|
||||
continue
|
||||
}
|
||||
if ex.url.Path != test.execPath {
|
||||
t.Errorf("%s: Did not get expected path for exec request", test.name)
|
||||
continue
|
||||
}
|
||||
if ex.method != "POST" {
|
||||
t.Errorf("%s: Did not get method for exec request: %s", test.name, ex.method)
|
||||
}
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == test.podPath && m == "GET":
|
||||
body := objBody(codec, test.pod)
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
default:
|
||||
t.Errorf("%s: unexpected request: %s %#v\n%#v", test.name, req.Method, req.URL, req)
|
||||
return nil, fmt.Errorf("unexpected request")
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
ex := &fakeRemoteExecutor{}
|
||||
if test.execErr {
|
||||
ex.execErr = fmt.Errorf("exec error")
|
||||
}
|
||||
params := &ExecOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
PodName: "foo",
|
||||
ContainerName: "bar",
|
||||
IOStreams: genericclioptions.NewTestIOStreamsDiscard(),
|
||||
},
|
||||
Executor: ex,
|
||||
}
|
||||
cmd := &cobra.Command{}
|
||||
args := []string{"test", "command"}
|
||||
if err := params.Complete(tf, cmd, args, -1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err := params.Run()
|
||||
if test.execErr && err != ex.execErr {
|
||||
t.Errorf("%s: Unexpected exec error: %v", test.name, err)
|
||||
return
|
||||
}
|
||||
if !test.execErr && err != nil {
|
||||
t.Errorf("%s: Unexpected error: %v", test.name, err)
|
||||
return
|
||||
}
|
||||
if test.execErr {
|
||||
return
|
||||
}
|
||||
if ex.url.Path != test.execPath {
|
||||
t.Errorf("%s: Did not get expected path for exec request", test.name)
|
||||
return
|
||||
}
|
||||
if ex.method != "POST" {
|
||||
t.Errorf("%s: Did not get method for exec request: %s", test.name, ex.method)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -270,16 +271,14 @@ func execPod() *api.Pod {
|
||||
}
|
||||
|
||||
func TestSetupTTY(t *testing.T) {
|
||||
stderr := &bytes.Buffer{}
|
||||
streams, _, _, stderr := genericclioptions.NewTestIOStreams()
|
||||
|
||||
// test 1 - don't attach stdin
|
||||
o := &StreamOptions{
|
||||
// InterruptParent: ,
|
||||
Stdin: false,
|
||||
In: &bytes.Buffer{},
|
||||
Out: &bytes.Buffer{},
|
||||
Err: stderr,
|
||||
TTY: true,
|
||||
Stdin: false,
|
||||
IOStreams: streams,
|
||||
TTY: true,
|
||||
}
|
||||
|
||||
tty := o.setupTTY()
|
||||
@ -327,7 +326,7 @@ func TestSetupTTY(t *testing.T) {
|
||||
// test 3 - request a TTY, but stdin is not a terminal
|
||||
o.Stdin = true
|
||||
o.In = &bytes.Buffer{}
|
||||
o.Err = stderr
|
||||
o.ErrOut = stderr
|
||||
o.TTY = true
|
||||
|
||||
tty = o.setupTTY()
|
||||
|
85
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/explain.go
generated
vendored
85
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/explain.go
generated
vendored
@ -18,14 +18,16 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
"k8s.io/kubernetes/pkg/kubectl/explain"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -49,43 +51,79 @@ var (
|
||||
kubectl explain pods.spec.containers`))
|
||||
)
|
||||
|
||||
type ExplainOptions struct {
|
||||
genericclioptions.IOStreams
|
||||
|
||||
CmdParent string
|
||||
ApiVersion string
|
||||
Recursive bool
|
||||
|
||||
Mapper meta.RESTMapper
|
||||
Schema openapi.Resources
|
||||
}
|
||||
|
||||
func NewExplainOptions(parent string, streams genericclioptions.IOStreams) *ExplainOptions {
|
||||
return &ExplainOptions{
|
||||
IOStreams: streams,
|
||||
CmdParent: parent,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCmdExplain returns a cobra command for swagger docs
|
||||
func NewCmdExplain(f cmdutil.Factory, out, cmdErr io.Writer) *cobra.Command {
|
||||
func NewCmdExplain(parent string, f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewExplainOptions(parent, streams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "explain RESOURCE",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Documentation of resources"),
|
||||
Long: explainLong + "\n\n" + cmdutil.ValidResourceTypeList(f),
|
||||
Long: explainLong + "\n\n" + cmdutil.SuggestApiResources(parent),
|
||||
Example: explainExamples,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := RunExplain(f, out, cmdErr, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.Validate(args))
|
||||
cmdutil.CheckErr(o.Run(args))
|
||||
},
|
||||
}
|
||||
cmd.Flags().Bool("recursive", false, "Print the fields of fields (Currently only 1 level deep)")
|
||||
cmd.Flags().String("api-version", "", "Get different explanations for particular API version")
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
cmd.Flags().BoolVar(&o.Recursive, "recursive", o.Recursive, "Print the fields of fields (Currently only 1 level deep)")
|
||||
cmd.Flags().StringVar(&o.ApiVersion, "api-version", o.ApiVersion, "Get different explanations for particular API version")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// RunExplain executes the appropriate steps to print a model's documentation
|
||||
func RunExplain(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *ExplainOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
var err error
|
||||
o.Mapper, err = f.ToRESTMapper()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Schema, err = f.OpenAPISchema()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ExplainOptions) Validate(args []string) error {
|
||||
if len(args) == 0 {
|
||||
fmt.Fprintf(cmdErr, "You must specify the type of resource to explain. %s\n", cmdutil.ValidResourceTypeList(f))
|
||||
return cmdutil.UsageErrorf(cmd, "Required resource not specified.")
|
||||
return fmt.Errorf("You must specify the type of resource to explain. %s\n", cmdutil.SuggestApiResources(o.CmdParent))
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return cmdutil.UsageErrorf(cmd, "We accept only this format: explain RESOURCE")
|
||||
return fmt.Errorf("We accept only this format: explain RESOURCE\n")
|
||||
}
|
||||
|
||||
recursive := cmdutil.GetFlagBool(cmd, "recursive")
|
||||
apiVersionString := cmdutil.GetFlagString(cmd, "api-version")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run executes the appropriate steps to print a model's documentation
|
||||
func (o *ExplainOptions) Run(args []string) error {
|
||||
recursive := o.Recursive
|
||||
apiVersionString := o.ApiVersion
|
||||
|
||||
mapper, _ := f.Object()
|
||||
// TODO: After we figured out the new syntax to separate group and resource, allow
|
||||
// the users to use it in explain (kubectl explain <group><syntax><resource>).
|
||||
// Refer to issue #16039 for why we do this. Refer to PR #15808 that used "/" syntax.
|
||||
inModel, fieldsPath, err := explain.SplitAndParseResourceRequest(args[0], mapper)
|
||||
inModel, fieldsPath, err := explain.SplitAndParseResourceRequest(args[0], o.Mapper)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -94,10 +132,10 @@ func RunExplain(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, ar
|
||||
fullySpecifiedGVR, groupResource := schema.ParseResourceArg(inModel)
|
||||
gvk := schema.GroupVersionKind{}
|
||||
if fullySpecifiedGVR != nil {
|
||||
gvk, _ = mapper.KindFor(*fullySpecifiedGVR)
|
||||
gvk, _ = o.Mapper.KindFor(*fullySpecifiedGVR)
|
||||
}
|
||||
if gvk.Empty() {
|
||||
gvk, err = mapper.KindFor(groupResource.WithVersion(""))
|
||||
gvk, err = o.Mapper.KindFor(groupResource.WithVersion(""))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -111,15 +149,10 @@ func RunExplain(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, ar
|
||||
gvk = apiVersion.WithKind(gvk.Kind)
|
||||
}
|
||||
|
||||
resources, err := f.OpenAPISchema()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
schema := resources.LookupResource(gvk)
|
||||
schema := o.Schema.LookupResource(gvk)
|
||||
if schema == nil {
|
||||
return fmt.Errorf("Couldn't find resource for %q", gvk)
|
||||
}
|
||||
|
||||
return explain.PrintModelDescription(fieldsPath, out, schema, gvk, recursive)
|
||||
return explain.PrintModelDescription(fieldsPath, o.Out, schema, gvk, recursive)
|
||||
}
|
||||
|
183
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/expose.go
generated
vendored
183
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/expose.go
generated
vendored
@ -17,18 +17,27 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -72,8 +81,44 @@ var (
|
||||
kubectl expose deployment nginx --port=80 --target-port=8000`))
|
||||
)
|
||||
|
||||
func NewCmdExposeService(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := &resource.FilenameOptions{}
|
||||
type ExposeServiceOptions struct {
|
||||
FilenameOptions resource.FilenameOptions
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
DryRun bool
|
||||
EnforceNamespace bool
|
||||
|
||||
Generators func(string) map[string]kubectl.Generator
|
||||
CanBeExposed polymorphichelpers.CanBeExposedFunc
|
||||
ClientForMapping func(*meta.RESTMapping) (resource.RESTClient, error)
|
||||
MapBasedSelectorForObject func(runtime.Object) (string, error)
|
||||
PortsForObject polymorphichelpers.PortsForObjectFunc
|
||||
ProtocolsForObject func(runtime.Object) (map[string]string, error)
|
||||
|
||||
Namespace string
|
||||
Mapper meta.RESTMapper
|
||||
|
||||
DynamicClient dynamic.Interface
|
||||
Builder *resource.Builder
|
||||
|
||||
Recorder genericclioptions.Recorder
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewExposeServiceOptions(ioStreams genericclioptions.IOStreams) *ExposeServiceOptions {
|
||||
return &ExposeServiceOptions{
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
PrintFlags: genericclioptions.NewPrintFlags("exposed").WithTypeSetter(scheme.Scheme),
|
||||
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdExposeService(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewExposeServiceOptions(streams)
|
||||
|
||||
validArgs := []string{}
|
||||
resources := regexp.MustCompile(`\s*,`).Split(exposeResources, -1)
|
||||
@ -88,13 +133,15 @@ func NewCmdExposeService(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
Long: exposeLong,
|
||||
Example: exposeExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := RunExpose(f, out, cmd, args, options)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.RunExpose(cmd, args))
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
ValidArgs: validArgs,
|
||||
}
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmd.Flags().String("generator", "service/v2", i18n.T("The name of the API generator to use. There are 2 generators: 'service/v1' and 'service/v2'. The only difference between them is that service port in v1 is named 'default', while it is left unnamed in v2. Default is 'service/v2'."))
|
||||
cmd.Flags().String("protocol", "", i18n.T("The network protocol for the service to be created. Default is 'TCP'."))
|
||||
cmd.Flags().String("port", "", i18n.T("The port that the service should serve on. Copied from the resource being exposed, if unspecified"))
|
||||
@ -112,36 +159,73 @@ func NewCmdExposeService(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
cmd.Flags().String("cluster-ip", "", i18n.T("ClusterIP to be assigned to the service. Leave empty to auto-allocate, or set to 'None' to create a headless service."))
|
||||
|
||||
usage := "identifying the resource to expose a service"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, options, usage)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunExpose(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions) error {
|
||||
namespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
func (o *ExposeServiceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.PrintObj = printer.PrintObj
|
||||
|
||||
o.RecordFlags.Complete(cmd)
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
r := f.NewBuilder().
|
||||
Internal().
|
||||
o.DynamicClient, err = f.DynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Generators = cmdutil.GeneratorFn
|
||||
o.Builder = f.NewBuilder()
|
||||
o.CanBeExposed = polymorphichelpers.CanBeExposedFn
|
||||
o.ClientForMapping = f.ClientForMapping
|
||||
o.MapBasedSelectorForObject = polymorphichelpers.MapBasedSelectorForObjectFn
|
||||
o.ProtocolsForObject = polymorphichelpers.ProtocolsForObjectFn
|
||||
o.PortsForObject = polymorphichelpers.PortsForObjectFn
|
||||
|
||||
o.Mapper, err = f.ToRESTMapper()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *ExposeServiceOptions) RunExpose(cmd *cobra.Command, args []string) error {
|
||||
r := o.Builder.
|
||||
WithScheme(legacyscheme.Scheme).
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
FilenameParam(o.EnforceNamespace, &o.FilenameOptions).
|
||||
ResourceTypeOrNameArgs(false, args...).
|
||||
Flatten().
|
||||
Do()
|
||||
err = r.Err()
|
||||
err := r.Err()
|
||||
if err != nil {
|
||||
return cmdutil.UsageErrorf(cmd, err.Error())
|
||||
}
|
||||
|
||||
// Get the generator, setup and validate all required parameters
|
||||
generatorName := cmdutil.GetFlagString(cmd, "generator")
|
||||
generators := f.Generators("expose")
|
||||
generators := o.Generators("expose")
|
||||
generator, found := generators[generatorName]
|
||||
if !found {
|
||||
return cmdutil.UsageErrorf(cmd, "generator %q not found.", generatorName)
|
||||
@ -154,7 +238,7 @@ func RunExpose(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
||||
}
|
||||
|
||||
mapping := info.ResourceMapping()
|
||||
if err := f.CanBeExposed(mapping.GroupVersionKind.GroupKind()); err != nil {
|
||||
if err := o.CanBeExposed(mapping.GroupVersionKind.GroupKind()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -168,7 +252,7 @@ func RunExpose(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
||||
// For objects that need a pod selector, derive it from the exposed object in case a user
|
||||
// didn't explicitly specify one via --selector
|
||||
if s, found := params["selector"]; found && kubectl.IsZero(s) {
|
||||
s, err := f.MapBasedSelectorForObject(info.Object)
|
||||
s, err := o.MapBasedSelectorForObject(info.Object)
|
||||
if err != nil {
|
||||
return cmdutil.UsageErrorf(cmd, "couldn't retrieve selectors via --selector flag or introspection: %v", err)
|
||||
}
|
||||
@ -180,7 +264,7 @@ func RunExpose(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
||||
// For objects that need a port, derive it from the exposed object in case a user
|
||||
// didn't explicitly specify one via --port
|
||||
if port, found := params["port"]; found && kubectl.IsZero(port) {
|
||||
ports, err := f.PortsForObject(info.Object)
|
||||
ports, err := o.PortsForObject(info.Object)
|
||||
if err != nil {
|
||||
return cmdutil.UsageErrorf(cmd, "couldn't find port via --port flag or introspection: %v", err)
|
||||
}
|
||||
@ -199,7 +283,7 @@ func RunExpose(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
||||
// Always try to derive protocols from the exposed object, may use
|
||||
// different protocols for different ports.
|
||||
if _, found := params["protocol"]; found {
|
||||
protocolsMap, err := f.ProtocolsForObject(info.Object)
|
||||
protocolsMap, err := o.ProtocolsForObject(info.Object)
|
||||
if err != nil {
|
||||
return cmdutil.UsageErrorf(cmd, "couldn't find protocol via introspection: %v", err)
|
||||
}
|
||||
@ -209,7 +293,7 @@ func RunExpose(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
||||
}
|
||||
|
||||
if kubectl.IsZero(params["labels"]) {
|
||||
labels, err := f.LabelsForObject(info.Object)
|
||||
labels, err := meta.NewAccessor().Labels(info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -237,45 +321,36 @@ func RunExpose(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
||||
}
|
||||
}
|
||||
|
||||
resourceMapper := &resource.Mapper{
|
||||
ObjectTyper: typer,
|
||||
RESTMapper: mapper,
|
||||
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
|
||||
Decoder: cmdutil.InternalVersionDecoder(),
|
||||
if err := o.Recorder.Record(object); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
info, err = resourceMapper.InfoForObject(object, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
if o.DryRun {
|
||||
return o.PrintObj(object, o.Out)
|
||||
}
|
||||
if cmdutil.ShouldRecord(cmd, info) {
|
||||
if err := cmdutil.RecordChangeCause(object, f.Command(cmd, false)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
info.Refresh(object, true)
|
||||
if cmdutil.GetDryRunFlag(cmd) {
|
||||
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
|
||||
return cmdutil.PrintObject(cmd, object, out)
|
||||
}
|
||||
cmdutil.PrintSuccess(false, out, info.Object, true, "exposed")
|
||||
return nil
|
||||
}
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), object, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
asUnstructured := &unstructured.Unstructured{}
|
||||
if err := legacyscheme.Scheme.Convert(object, asUnstructured, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
gvks, _, err := unstructuredscheme.NewUnstructuredObjectTyper().ObjectKinds(asUnstructured)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
objMapping, err := o.Mapper.RESTMapping(gvks[0].GroupKind(), gvks[0].Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Serialize the object with the annotation applied.
|
||||
object, err = resource.NewHelper(info.Client, info.Mapping).Create(namespace, false, object)
|
||||
actualObject, err := o.DynamicClient.Resource(objMapping.Resource).Namespace(o.Namespace).Create(asUnstructured)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
|
||||
return cmdutil.PrintObject(cmd, object, out)
|
||||
}
|
||||
|
||||
cmdutil.PrintSuccess(false, out, info.Object, false, "exposed")
|
||||
return nil
|
||||
return o.PrintObj(actualObject, o.Out)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
85
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/expose_test.go
generated
vendored
85
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/expose_test.go
generated
vendored
@ -17,7 +17,6 @@ limitations under the License.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
@ -31,6 +30,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
@ -79,7 +79,7 @@ func TestRunExposeService(t *testing.T) {
|
||||
Selector: map[string]string{"app": "go"},
|
||||
},
|
||||
},
|
||||
expected: "service \"foo\" exposed",
|
||||
expected: "service/foo exposed",
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
@ -110,7 +110,7 @@ func TestRunExposeService(t *testing.T) {
|
||||
Selector: map[string]string{"func": "stream"},
|
||||
},
|
||||
},
|
||||
expected: "service \"foo\" exposed",
|
||||
expected: "service/foo exposed",
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
@ -142,7 +142,7 @@ func TestRunExposeService(t *testing.T) {
|
||||
Selector: map[string]string{"run": "this"},
|
||||
},
|
||||
},
|
||||
expected: "service \"mayor\" exposed",
|
||||
expected: "service/mayor exposed",
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
@ -237,7 +237,7 @@ func TestRunExposeService(t *testing.T) {
|
||||
ClusterIP: "10.10.10.10",
|
||||
},
|
||||
},
|
||||
expected: "service \"foo\" exposed",
|
||||
expected: "service /foo exposed",
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
@ -269,7 +269,7 @@ func TestRunExposeService(t *testing.T) {
|
||||
ClusterIP: api.ClusterIPNone,
|
||||
},
|
||||
},
|
||||
expected: "service \"foo\" exposed",
|
||||
expected: "service/foo exposed",
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
@ -295,7 +295,7 @@ func TestRunExposeService(t *testing.T) {
|
||||
ClusterIP: api.ClusterIPNone,
|
||||
},
|
||||
},
|
||||
expected: "service \"foo\" exposed",
|
||||
expected: "service/foo exposed",
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
@ -312,7 +312,7 @@ func TestRunExposeService(t *testing.T) {
|
||||
Selector: map[string]string{"app": "go"},
|
||||
},
|
||||
},
|
||||
flags: map[string]string{"filename": "../../../examples/guestbook/redis-master-service.yaml", "selector": "func=stream", "protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test", "dry-run": "true"},
|
||||
flags: map[string]string{"filename": "../../../test/e2e/testing-manifests/guestbook/redis-master-service.yaml", "selector": "func=stream", "protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test", "dry-run": "true"},
|
||||
output: &api.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Labels: map[string]string{"svc": "test"}},
|
||||
Spec: api.ServiceSpec{
|
||||
@ -353,7 +353,7 @@ func TestRunExposeService(t *testing.T) {
|
||||
Selector: map[string]string{"svc": "frompod"},
|
||||
},
|
||||
},
|
||||
expected: "service \"a-name-that-is-toooo-big-for-a-service-because-it-can-only-hand\" exposed",
|
||||
expected: "service/a-name-that-is-toooo-big-for-a-service-because-it-can-only-hand exposed",
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
@ -466,42 +466,43 @@ func TestRunExposeService(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
ns := legacyscheme.Codecs
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace(test.ns)
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Version: "v1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == test.calls[m] && m == "GET":
|
||||
return &http.Response{StatusCode: test.status, Header: defaultHeader(), Body: objBody(codec, test.input)}, nil
|
||||
case p == test.calls[m] && m == "POST":
|
||||
return &http.Response{StatusCode: test.status, Header: defaultHeader(), Body: objBody(codec, test.output)}, nil
|
||||
default:
|
||||
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
return nil, nil
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = test.ns
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
cmd := NewCmdExposeService(tf, buf)
|
||||
cmd.SetOutput(buf)
|
||||
for flag, value := range test.flags {
|
||||
cmd.Flags().Set(flag, value)
|
||||
}
|
||||
cmd.Run(cmd, test.args)
|
||||
tf.Client = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Version: "v1"},
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == test.calls[m] && m == "GET":
|
||||
return &http.Response{StatusCode: test.status, Header: defaultHeader(), Body: objBody(codec, test.input)}, nil
|
||||
default:
|
||||
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
return nil, nil
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
out := buf.String()
|
||||
if _, ok := test.flags["dry-run"]; ok {
|
||||
test.expected = fmt.Sprintf("service %q exposed (dry run)", test.flags["name"])
|
||||
}
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdExposeService(tf, ioStreams)
|
||||
cmd.SetOutput(buf)
|
||||
for flag, value := range test.flags {
|
||||
cmd.Flags().Set(flag, value)
|
||||
}
|
||||
cmd.Run(cmd, test.args)
|
||||
|
||||
if !strings.Contains(out, test.expected) {
|
||||
t.Errorf("%s: Unexpected output! Expected\n%s\ngot\n%s", test.name, test.expected, out)
|
||||
}
|
||||
out := buf.String()
|
||||
if _, ok := test.flags["dry-run"]; ok {
|
||||
test.expected = fmt.Sprintf("service/%s exposed (dry run)", test.flags["name"])
|
||||
}
|
||||
|
||||
if !strings.Contains(out, test.expected) {
|
||||
t.Errorf("%s: Unexpected output! Expected\n%s\ngot\n%s", test.name, test.expected, out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,41 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["get.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/resource",
|
||||
srcs = [
|
||||
"get.go",
|
||||
"get_flags.go",
|
||||
"humanreadable_flags.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/get",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/cmd/templates:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/openapi:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/resource:go_default_library",
|
||||
"//pkg/kubectl/scheme:go_default_library",
|
||||
"//pkg/kubectl/util/i18n:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//pkg/printers/internalversion:go_default_library",
|
||||
"//pkg/util/interrupt:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
@ -33,17 +55,18 @@ go_library(
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["get_test.go"],
|
||||
srcs = [
|
||||
"get_test.go",
|
||||
"humanreadable_flags_test.go",
|
||||
],
|
||||
data = [
|
||||
"//api/openapi-spec:swagger-spec",
|
||||
"//examples:config",
|
||||
"//test/e2e/testing-manifests:all-srcs",
|
||||
"//test/fixtures",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/api/testing:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/core/v1:go_default_library",
|
||||
@ -51,33 +74,20 @@ go_test(
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/openapi:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/openapi/testing:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/resource:go_default_library",
|
||||
"//pkg/kubectl/scheme:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest/watch:go_default_library",
|
||||
"//vendor/k8s.io/kube-openapi/pkg/util/proto: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"],
|
||||
)
|
@ -14,19 +14,17 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resource
|
||||
package get
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"net/url"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"net/url"
|
||||
|
||||
kapierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@ -38,12 +36,13 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util/interrupt"
|
||||
@ -51,7 +50,12 @@ import (
|
||||
|
||||
// GetOptions contains the input to the get command.
|
||||
type GetOptions struct {
|
||||
Out, ErrOut io.Writer
|
||||
PrintFlags *PrintFlags
|
||||
ToPrinter func(*meta.RESTMapping, bool) (printers.ResourcePrinterFunc, error)
|
||||
IsHumanReadablePrinter bool
|
||||
PrintWithOpenAPICols bool
|
||||
|
||||
CmdParent string
|
||||
|
||||
resource.FilenameOptions
|
||||
|
||||
@ -68,13 +72,14 @@ type GetOptions struct {
|
||||
|
||||
ServerPrint bool
|
||||
|
||||
NoHeaders bool
|
||||
Sort bool
|
||||
IgnoreNotFound bool
|
||||
ShowKind bool
|
||||
LabelColumns []string
|
||||
Export bool
|
||||
|
||||
IncludeUninitialized bool
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
@ -86,10 +91,7 @@ var (
|
||||
desired resource type is namespaced you will only see results in your current
|
||||
namespace unless you pass --all-namespaces.
|
||||
|
||||
This command will hide resources that have completed, such as pods that are
|
||||
in the Succeeded or Failed phases. You can see the full results for any
|
||||
resource by providing the --show-all flag. Uninitialized objects are not
|
||||
shown unless --include-uninitialized is passed.
|
||||
Uninitialized objects are not shown unless --include-uninitialized is passed.
|
||||
|
||||
By specifying the output as 'template' and providing a Go template as the value
|
||||
of the --template flag, you can filter the attributes of the fetched resources.`)
|
||||
@ -104,6 +106,9 @@ var (
|
||||
# List a single replication controller with specified NAME in ps output format.
|
||||
kubectl get replicationcontroller web
|
||||
|
||||
# List deployments in JSON output format, in the "v1" version of the "apps" API group:
|
||||
kubectl get deployments.v1.apps -o json
|
||||
|
||||
# List a single pod in JSON output format.
|
||||
kubectl get -o json pod web-pod-13je7
|
||||
|
||||
@ -117,98 +122,144 @@ var (
|
||||
kubectl get rc,services
|
||||
|
||||
# List one or more resources by their type and names.
|
||||
kubectl get rc/web service/frontend pods/web-pod-13je7
|
||||
|
||||
# List all resources with different types.
|
||||
kubectl get all`))
|
||||
kubectl get rc/web service/frontend pods/web-pod-13je7`))
|
||||
)
|
||||
|
||||
const (
|
||||
useOpenAPIPrintColumnFlagLabel = "use-openapi-print-columns"
|
||||
useServerPrintColumns = "experimental-server-print"
|
||||
useServerPrintColumns = "server-print"
|
||||
)
|
||||
|
||||
// NewGetOptions returns a GetOptions with default chunk size 500.
|
||||
func NewGetOptions(parent string, streams genericclioptions.IOStreams) *GetOptions {
|
||||
return &GetOptions{
|
||||
PrintFlags: NewGetPrintFlags(),
|
||||
CmdParent: parent,
|
||||
|
||||
IOStreams: streams,
|
||||
ChunkSize: 500,
|
||||
ServerPrint: true,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCmdGet creates a command object for the generic "get" action, which
|
||||
// retrieves one or more resources from a server.
|
||||
func NewCmdGet(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command {
|
||||
options := &GetOptions{
|
||||
Out: out,
|
||||
ErrOut: errOut,
|
||||
}
|
||||
validArgs := cmdutil.ValidArgList(f)
|
||||
func NewCmdGet(parent string, f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewGetOptions(parent, streams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "get [(-o|--output=)json|yaml|wide|custom-columns=...|custom-columns-file=...|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=...] (TYPE [NAME | -l label] | TYPE/NAME ...) [flags]",
|
||||
Use: "get [(-o|--output=)json|yaml|wide|custom-columns=...|custom-columns-file=...|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=...] (TYPE[.VERSION][.GROUP] [NAME | -l label] | TYPE[.VERSION][.GROUP]/NAME ...) [flags]",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Display one or many resources"),
|
||||
Long: getLong + "\n\n" + cmdutil.ValidResourceTypeList(f),
|
||||
Long: getLong + "\n\n" + cmdutil.SuggestApiResources(parent),
|
||||
Example: getExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Validate(cmd))
|
||||
cmdutil.CheckErr(options.Run(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate(cmd))
|
||||
cmdutil.CheckErr(o.Run(f, cmd, args))
|
||||
},
|
||||
SuggestFor: []string{"list", "ps"},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
}
|
||||
|
||||
cmd.Flags().StringVar(&options.Raw, "raw", options.Raw, "Raw URI to request from the server. Uses the transport specified by the kubeconfig file.")
|
||||
cmd.Flags().BoolVarP(&options.Watch, "watch", "w", options.Watch, "After listing/getting the requested object, watch for changes. Uninitialized objects are excluded if no object name is provided.")
|
||||
cmd.Flags().BoolVar(&options.WatchOnly, "watch-only", options.WatchOnly, "Watch for changes to the requested object(s), without listing/getting first.")
|
||||
cmd.Flags().Int64Var(&options.ChunkSize, "chunk-size", 500, "Return large lists in chunks rather than all at once. Pass 0 to disable. This flag is beta and may change in the future.")
|
||||
cmd.Flags().BoolVar(&options.IgnoreNotFound, "ignore-not-found", options.IgnoreNotFound, "If the requested object does not exist the command will return exit code 0.")
|
||||
cmd.Flags().StringVarP(&options.LabelSelector, "selector", "l", options.LabelSelector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().StringVar(&options.FieldSelector, "field-selector", options.FieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.")
|
||||
cmd.Flags().BoolVar(&options.AllNamespaces, "all-namespaces", options.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmd.Flags().StringVar(&o.Raw, "raw", o.Raw, "Raw URI to request from the server. Uses the transport specified by the kubeconfig file.")
|
||||
cmd.Flags().BoolVarP(&o.Watch, "watch", "w", o.Watch, "After listing/getting the requested object, watch for changes. Uninitialized objects are excluded if no object name is provided.")
|
||||
cmd.Flags().BoolVar(&o.WatchOnly, "watch-only", o.WatchOnly, "Watch for changes to the requested object(s), without listing/getting first.")
|
||||
cmd.Flags().Int64Var(&o.ChunkSize, "chunk-size", o.ChunkSize, "Return large lists in chunks rather than all at once. Pass 0 to disable. This flag is beta and may change in the future.")
|
||||
cmd.Flags().BoolVar(&o.IgnoreNotFound, "ignore-not-found", o.IgnoreNotFound, "If the requested object does not exist the command will return exit code 0.")
|
||||
cmd.Flags().StringVarP(&o.LabelSelector, "selector", "l", o.LabelSelector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().StringVar(&o.FieldSelector, "field-selector", o.FieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.")
|
||||
cmd.Flags().BoolVar(&o.AllNamespaces, "all-namespaces", o.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
addOpenAPIPrintColumnFlags(cmd)
|
||||
addServerPrintColumnFlags(cmd)
|
||||
cmd.Flags().BoolVar(&options.ShowKind, "show-kind", options.ShowKind, "If present, list the resource type for the requested object(s).")
|
||||
cmd.Flags().StringSliceVarP(&options.LabelColumns, "label-columns", "L", options.LabelColumns, "Accepts a comma separated list of labels that are going to be presented as columns. Names are case-sensitive. You can also use multiple flag options like -L label1 -L label2...")
|
||||
cmd.Flags().BoolVar(&options.Export, "export", options.Export, "If true, use 'export' for the resources. Exported resources are stripped of cluster-specific information.")
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, "identifying the resource to get from a server.")
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
addOpenAPIPrintColumnFlags(cmd, o)
|
||||
addServerPrintColumnFlags(cmd, o)
|
||||
cmd.Flags().BoolVar(&o.Export, "export", o.Export, "If true, use 'export' for the resources. Exported resources are stripped of cluster-specific information.")
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "identifying the resource to get from a server.")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Complete takes the command arguments and factory and infers any remaining options.
|
||||
func (options *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
if len(options.Raw) > 0 {
|
||||
func (o *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
if len(o.Raw) > 0 {
|
||||
if len(args) > 0 {
|
||||
return fmt.Errorf("arguments may not be passed when --raw is specified")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
options.ServerPrint = cmdutil.GetFlagBool(cmd, useServerPrintColumns)
|
||||
|
||||
var err error
|
||||
options.Namespace, options.ExplicitNamespace, err = f.DefaultNamespace()
|
||||
o.Namespace, o.ExplicitNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if options.AllNamespaces {
|
||||
options.ExplicitNamespace = false
|
||||
if o.AllNamespaces {
|
||||
o.ExplicitNamespace = false
|
||||
}
|
||||
|
||||
isSorting, err := cmd.Flags().GetString("sort-by")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options.Sort = len(isSorting) > 0
|
||||
o.Sort = len(isSorting) > 0
|
||||
|
||||
options.IncludeUninitialized = cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
o.NoHeaders = cmdutil.GetFlagBool(cmd, "no-headers")
|
||||
|
||||
// TODO (soltysh): currently we don't support sorting and custom columns
|
||||
// with server side print. So in these cases force the old behavior.
|
||||
outputOption := cmd.Flags().Lookup("output").Value.String()
|
||||
if o.Sort && outputOption == "custom-columns" {
|
||||
o.ServerPrint = false
|
||||
}
|
||||
|
||||
templateArg := ""
|
||||
if o.PrintFlags.TemplateFlags != nil && o.PrintFlags.TemplateFlags.TemplateArgument != nil {
|
||||
templateArg = *o.PrintFlags.TemplateFlags.TemplateArgument
|
||||
}
|
||||
|
||||
// human readable printers have special conversion rules, so we determine if we're using one.
|
||||
if (len(*o.PrintFlags.OutputFormat) == 0 && len(templateArg) == 0) || *o.PrintFlags.OutputFormat == "wide" {
|
||||
o.IsHumanReadablePrinter = true
|
||||
}
|
||||
|
||||
o.IncludeUninitialized = cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
|
||||
if resource.MultipleTypesRequested(args) {
|
||||
o.PrintFlags.EnsureWithKind()
|
||||
}
|
||||
o.ToPrinter = func(mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinterFunc, error) {
|
||||
// make a new copy of current flags / opts before mutating
|
||||
printFlags := o.PrintFlags.Copy()
|
||||
|
||||
if mapping != nil {
|
||||
if !cmdSpecifiesOutputFmt(cmd) && o.PrintWithOpenAPICols {
|
||||
if apiSchema, err := f.OpenAPISchema(); err == nil {
|
||||
printFlags.UseOpenAPIColumns(apiSchema, mapping)
|
||||
}
|
||||
}
|
||||
printFlags.SetKind(mapping.GroupVersionKind.GroupKind())
|
||||
}
|
||||
if withNamespace {
|
||||
printFlags.EnsureWithNamespace()
|
||||
}
|
||||
|
||||
printer, err := printFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
printer = maybeWrapSortingPrinter(printer, isSorting)
|
||||
return printer.PrintObj, nil
|
||||
}
|
||||
|
||||
switch {
|
||||
case options.Watch || options.WatchOnly:
|
||||
case o.Watch || o.WatchOnly:
|
||||
// include uninitialized objects when watching on a single object
|
||||
// unless explicitly set --include-uninitialized=false
|
||||
options.IncludeUninitialized = cmdutil.ShouldIncludeUninitialized(cmd, len(args) == 2)
|
||||
o.IncludeUninitialized = cmdutil.ShouldIncludeUninitialized(cmd, len(args) == 2)
|
||||
default:
|
||||
if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(options.Filenames) {
|
||||
fmt.Fprint(options.ErrOut, "You must specify the type of resource to get. ", cmdutil.ValidResourceTypeList(f))
|
||||
if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(o.Filenames) {
|
||||
fmt.Fprintf(o.ErrOut, "You must specify the type of resource to get. %s\n\n", cmdutil.SuggestApiResources(o.CmdParent))
|
||||
fullCmdName := cmd.Parent().CommandPath()
|
||||
usageString := "Required resource not specified."
|
||||
if len(fullCmdName) > 0 && cmdutil.IsSiblingCommandExists(cmd, "explain") {
|
||||
@ -222,15 +273,15 @@ func (options *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
|
||||
}
|
||||
|
||||
// Validate checks the set of flags provided by the user.
|
||||
func (options *GetOptions) Validate(cmd *cobra.Command) error {
|
||||
if len(options.Raw) > 0 {
|
||||
if options.Watch || options.WatchOnly || len(options.LabelSelector) > 0 || options.Export {
|
||||
func (o *GetOptions) Validate(cmd *cobra.Command) error {
|
||||
if len(o.Raw) > 0 {
|
||||
if o.Watch || o.WatchOnly || len(o.LabelSelector) > 0 || o.Export {
|
||||
return fmt.Errorf("--raw may not be specified with other flags that filter the server request or alter the output")
|
||||
}
|
||||
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw and --output are mutually exclusive")
|
||||
}
|
||||
if _, err := url.ParseRequestURI(options.Raw); err != nil {
|
||||
if _, err := url.ParseRequestURI(o.Raw); err != nil {
|
||||
return cmdutil.UsageErrorf(cmd, "--raw must be a valid URL path: %v", err)
|
||||
}
|
||||
}
|
||||
@ -245,35 +296,33 @@ func (options *GetOptions) Validate(cmd *cobra.Command) error {
|
||||
|
||||
// Run performs the get operation.
|
||||
// TODO: remove the need to pass these arguments, like other commands.
|
||||
func (options *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
if len(options.Raw) > 0 {
|
||||
return options.raw(f)
|
||||
func (o *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
if len(o.Raw) > 0 {
|
||||
return o.raw(f)
|
||||
}
|
||||
if options.Watch || options.WatchOnly {
|
||||
return options.watch(f, cmd, args)
|
||||
}
|
||||
|
||||
printOpts := cmdutil.ExtractCmdPrintOptions(cmd, options.AllNamespaces)
|
||||
printer, err := cmdutil.PrinterForOptions(printOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
if o.Watch || o.WatchOnly {
|
||||
return o.watch(f, cmd, args)
|
||||
}
|
||||
|
||||
r := f.NewBuilder().
|
||||
Unstructured().
|
||||
NamespaceParam(options.Namespace).DefaultNamespace().AllNamespaces(options.AllNamespaces).
|
||||
FilenameParam(options.ExplicitNamespace, &options.FilenameOptions).
|
||||
LabelSelectorParam(options.LabelSelector).
|
||||
FieldSelectorParam(options.FieldSelector).
|
||||
ExportParam(options.Export).
|
||||
RequestChunksOf(options.ChunkSize).
|
||||
IncludeUninitialized(options.IncludeUninitialized).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().AllNamespaces(o.AllNamespaces).
|
||||
FilenameParam(o.ExplicitNamespace, &o.FilenameOptions).
|
||||
LabelSelectorParam(o.LabelSelector).
|
||||
FieldSelectorParam(o.FieldSelector).
|
||||
ExportParam(o.Export).
|
||||
RequestChunksOf(o.ChunkSize).
|
||||
IncludeUninitialized(o.IncludeUninitialized).
|
||||
ResourceTypeOrNameArgs(true, args...).
|
||||
ContinueOnError().
|
||||
Latest().
|
||||
Flatten().
|
||||
TransformRequests(func(req *rest.Request) {
|
||||
if options.ServerPrint && !printer.IsGeneric() && !options.Sort {
|
||||
// We need full objects if printing with openapi columns
|
||||
if o.PrintWithOpenAPICols {
|
||||
return
|
||||
}
|
||||
if o.ServerPrint && o.IsHumanReadablePrinter && !o.Sort {
|
||||
group := metav1beta1.GroupName
|
||||
version := metav1beta1.SchemeGroupVersion.Version
|
||||
|
||||
@ -283,21 +332,15 @@ func (options *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []str
|
||||
}).
|
||||
Do()
|
||||
|
||||
if options.IgnoreNotFound {
|
||||
if o.IgnoreNotFound {
|
||||
r.IgnoreErrors(kapierrors.IsNotFound)
|
||||
}
|
||||
if err := r.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filterOpts := cmdutil.ExtractCmdPrintOptions(cmd, options.AllNamespaces)
|
||||
filterFuncs := f.DefaultResourceFilterFunc()
|
||||
if r.TargetsSingleItems() {
|
||||
filterFuncs = nil
|
||||
}
|
||||
|
||||
if printer.IsGeneric() {
|
||||
return options.printGeneric(printer, r, filterFuncs, filterOpts)
|
||||
if !o.IsHumanReadablePrinter {
|
||||
return o.printGeneric(r)
|
||||
}
|
||||
|
||||
allErrs := []error{}
|
||||
@ -309,8 +352,8 @@ func (options *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []str
|
||||
|
||||
objs := make([]runtime.Object, len(infos))
|
||||
for ix := range infos {
|
||||
if options.ServerPrint {
|
||||
table, err := options.decodeIntoTable(cmdutil.InternalVersionJSONEncoder(), infos[ix].Object)
|
||||
if o.ServerPrint {
|
||||
table, err := o.decodeIntoTable(infos[ix].Object)
|
||||
if err == nil {
|
||||
infos[ix].Object = table
|
||||
} else {
|
||||
@ -328,36 +371,26 @@ func (options *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []str
|
||||
return err
|
||||
}
|
||||
var sorter *kubectl.RuntimeSort
|
||||
if options.Sort && len(objs) > 1 {
|
||||
if o.Sort && len(objs) > 1 {
|
||||
// TODO: questionable
|
||||
if sorter, err = kubectl.SortObjects(cmdutil.InternalVersionDecoder(), objs, sorting); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// use the default printer for each object
|
||||
printer = nil
|
||||
var printer printers.ResourcePrinter
|
||||
var lastMapping *meta.RESTMapping
|
||||
w := printers.GetNewTabWriter(options.Out)
|
||||
|
||||
useOpenAPIPrintColumns := cmdutil.GetFlagBool(cmd, useOpenAPIPrintColumnFlagLabel)
|
||||
|
||||
showKind := options.ShowKind || resource.MultipleTypesRequested(args) || cmdutil.MustPrintWithKinds(objs, infos, sorter)
|
||||
|
||||
filteredResourceCount := 0
|
||||
noHeaders := cmdutil.GetFlagBool(cmd, "no-headers")
|
||||
nonEmptyObjCount := 0
|
||||
w := printers.GetNewTabWriter(o.Out)
|
||||
for ix := range objs {
|
||||
var mapping *meta.RESTMapping
|
||||
var original runtime.Object
|
||||
var info *resource.Info
|
||||
if sorter != nil {
|
||||
info = infos[sorter.OriginalPosition(ix)]
|
||||
mapping = info.Mapping
|
||||
original = info.Object
|
||||
} else {
|
||||
info = infos[ix]
|
||||
mapping = info.Mapping
|
||||
original = info.Object
|
||||
}
|
||||
|
||||
// if dealing with a table that has no rows, skip remaining steps
|
||||
@ -368,24 +401,24 @@ func (options *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []str
|
||||
}
|
||||
}
|
||||
|
||||
nonEmptyObjCount++
|
||||
|
||||
printWithNamespace := o.AllNamespaces
|
||||
if mapping != nil && mapping.Scope.Name() == meta.RESTScopeNameRoot {
|
||||
printWithNamespace = false
|
||||
}
|
||||
|
||||
if shouldGetNewPrinterForMapping(printer, lastMapping, mapping) {
|
||||
if printer != nil {
|
||||
w.Flush()
|
||||
w.Flush()
|
||||
|
||||
// TODO: this doesn't belong here
|
||||
// add linebreak between resource groups (if there is more than one)
|
||||
// skip linebreak above first resource group
|
||||
if lastMapping != nil && !o.NoHeaders {
|
||||
fmt.Fprintln(o.ErrOut)
|
||||
}
|
||||
|
||||
printWithNamespace := options.AllNamespaces
|
||||
if mapping != nil && mapping.Scope.Name() == meta.RESTScopeNameRoot {
|
||||
printWithNamespace = false
|
||||
}
|
||||
|
||||
printOpts := cmdutil.ExtractCmdPrintOptions(cmd, printWithNamespace)
|
||||
// if cmd does not specify output format and useOpenAPIPrintColumnFlagLabel flag is true,
|
||||
// then get the default output options for this mapping from OpenAPI schema.
|
||||
if !cmdSpecifiesOutputFmt(cmd) && useOpenAPIPrintColumns {
|
||||
updatePrintOptionsForOpenAPI(f, mapping, printOpts)
|
||||
}
|
||||
|
||||
printer, err = cmdutil.PrinterForOptions(printOpts)
|
||||
printer, err = o.ToPrinter(mapping, printWithNamespace)
|
||||
if err != nil {
|
||||
if !errs.Has(err.Error()) {
|
||||
errs.Insert(err.Error())
|
||||
@ -394,103 +427,47 @@ func (options *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []str
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: this doesn't belong here
|
||||
// add linebreak between resource groups (if there is more than one)
|
||||
// skip linebreak above first resource group
|
||||
if lastMapping != nil && !noHeaders {
|
||||
fmt.Fprintf(options.ErrOut, "%s\n", "")
|
||||
}
|
||||
|
||||
lastMapping = mapping
|
||||
}
|
||||
|
||||
typedObj := info.AsInternal()
|
||||
|
||||
// filter objects if filter has been defined for current object
|
||||
if isFiltered, err := filterFuncs.Filter(typedObj, filterOpts); isFiltered {
|
||||
if err == nil {
|
||||
filteredResourceCount++
|
||||
continue
|
||||
}
|
||||
if !errs.Has(err.Error()) {
|
||||
errs.Insert(err.Error())
|
||||
allErrs = append(allErrs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if resourcePrinter, found := printer.(*printers.HumanReadablePrinter); found {
|
||||
resourceName := resourcePrinter.GetResourceKind()
|
||||
if mapping != nil {
|
||||
if resourceName == "" {
|
||||
resourceName = mapping.Resource
|
||||
}
|
||||
if alias, ok := kubectl.ResourceShortFormFor(mapping.Resource); ok {
|
||||
resourceName = alias
|
||||
} else if resourceName == "" {
|
||||
resourceName = "none"
|
||||
}
|
||||
} else {
|
||||
resourceName = "none"
|
||||
}
|
||||
|
||||
if showKind {
|
||||
resourcePrinter.EnsurePrintWithKind(resourceName)
|
||||
}
|
||||
|
||||
if err := printer.PrintObj(typedObj, w); err != nil {
|
||||
if !errs.Has(err.Error()) {
|
||||
errs.Insert(err.Error())
|
||||
allErrs = append(allErrs, err)
|
||||
}
|
||||
}
|
||||
// ensure a versioned object is passed to the custom-columns printer
|
||||
// if we are using OpenAPI columns to print
|
||||
if o.PrintWithOpenAPICols {
|
||||
printer.PrintObj(info.Object, w)
|
||||
continue
|
||||
}
|
||||
objToPrint := typedObj
|
||||
if printer.IsGeneric() {
|
||||
// use raw object as received from the builder when using generic
|
||||
// printer instead of decodedObj
|
||||
objToPrint = original
|
||||
}
|
||||
if err := printer.PrintObj(objToPrint, w); err != nil {
|
||||
if !errs.Has(err.Error()) {
|
||||
errs.Insert(err.Error())
|
||||
allErrs = append(allErrs, err)
|
||||
}
|
||||
continue
|
||||
|
||||
internalObj, err := legacyscheme.Scheme.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupKind().WithVersion(runtime.APIVersionInternal).GroupVersion())
|
||||
if err != nil {
|
||||
// if there's an error, try to print what you have (mirrors old behavior).
|
||||
glog.V(1).Info(err)
|
||||
printer.PrintObj(info.Object, w)
|
||||
} else {
|
||||
printer.PrintObj(internalObj, w)
|
||||
}
|
||||
}
|
||||
w.Flush()
|
||||
nonEmptyObjCount := 0
|
||||
for _, obj := range objs {
|
||||
if table, ok := obj.(*metav1beta1.Table); ok {
|
||||
// exclude any Table objects with empty rows from our total object count
|
||||
if len(table.Rows) == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
nonEmptyObjCount++
|
||||
if nonEmptyObjCount == 0 && !o.IgnoreNotFound {
|
||||
fmt.Fprintln(o.ErrOut, "No resources found.")
|
||||
}
|
||||
|
||||
cmdutil.PrintFilterCount(options.ErrOut, nonEmptyObjCount, filteredResourceCount, len(allErrs), filterOpts, options.IgnoreNotFound)
|
||||
return utilerrors.NewAggregate(allErrs)
|
||||
}
|
||||
|
||||
// raw makes a simple HTTP request to the provided path on the server using the default
|
||||
// credentials.
|
||||
func (options *GetOptions) raw(f cmdutil.Factory) error {
|
||||
func (o *GetOptions) raw(f cmdutil.Factory) error {
|
||||
restClient, err := f.RESTClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stream, err := restClient.Get().RequestURI(options.Raw).Stream()
|
||||
stream, err := restClient.Get().RequestURI(o.Raw).Stream()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer stream.Close()
|
||||
|
||||
_, err = io.Copy(options.Out, stream)
|
||||
_, err = io.Copy(o.Out, stream)
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
@ -499,16 +476,16 @@ func (options *GetOptions) raw(f cmdutil.Factory) error {
|
||||
|
||||
// watch starts a client-side watch of one or more resources.
|
||||
// TODO: remove the need for arguments here.
|
||||
func (options *GetOptions) watch(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
func (o *GetOptions) watch(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
r := f.NewBuilder().
|
||||
Unstructured().
|
||||
NamespaceParam(options.Namespace).DefaultNamespace().AllNamespaces(options.AllNamespaces).
|
||||
FilenameParam(options.ExplicitNamespace, &options.FilenameOptions).
|
||||
LabelSelectorParam(options.LabelSelector).
|
||||
FieldSelectorParam(options.FieldSelector).
|
||||
ExportParam(options.Export).
|
||||
RequestChunksOf(options.ChunkSize).
|
||||
IncludeUninitialized(options.IncludeUninitialized).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().AllNamespaces(o.AllNamespaces).
|
||||
FilenameParam(o.ExplicitNamespace, &o.FilenameOptions).
|
||||
LabelSelectorParam(o.LabelSelector).
|
||||
FieldSelectorParam(o.FieldSelector).
|
||||
ExportParam(o.Export).
|
||||
RequestChunksOf(o.ChunkSize).
|
||||
IncludeUninitialized(o.IncludeUninitialized).
|
||||
ResourceTypeOrNameArgs(true, args...).
|
||||
SingleResourceType().
|
||||
Latest().
|
||||
@ -541,16 +518,9 @@ func (options *GetOptions) watch(f cmdutil.Factory, cmd *cobra.Command, args []s
|
||||
}
|
||||
}
|
||||
|
||||
filterOpts := cmdutil.ExtractCmdPrintOptions(cmd, options.AllNamespaces)
|
||||
filterFuncs := f.DefaultResourceFilterFunc()
|
||||
if r.TargetsSingleItems() {
|
||||
filterFuncs = nil
|
||||
}
|
||||
|
||||
info := infos[0]
|
||||
mapping := info.ResourceMapping()
|
||||
printOpts := cmdutil.ExtractCmdPrintOptions(cmd, options.AllNamespaces)
|
||||
printer, err := cmdutil.PrinterForOptions(printOpts)
|
||||
printer, err := o.ToPrinter(mapping, o.AllNamespaces)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -568,16 +538,16 @@ func (options *GetOptions) watch(f cmdutil.Factory, cmd *cobra.Command, args []s
|
||||
if isList {
|
||||
// the resourceVersion of list objects is ~now but won't return
|
||||
// an initial watch event
|
||||
rv, err = mapping.MetadataAccessor.ResourceVersion(obj)
|
||||
rv, err = meta.NewAccessor().ResourceVersion(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// print the current object
|
||||
if !options.WatchOnly {
|
||||
if !o.WatchOnly {
|
||||
var objsToPrint []runtime.Object
|
||||
writer := printers.GetNewTabWriter(options.Out)
|
||||
writer := printers.GetNewTabWriter(o.Out)
|
||||
|
||||
if isList {
|
||||
objsToPrint, _ = meta.ExtractList(obj)
|
||||
@ -585,18 +555,13 @@ func (options *GetOptions) watch(f cmdutil.Factory, cmd *cobra.Command, args []s
|
||||
objsToPrint = append(objsToPrint, obj)
|
||||
}
|
||||
for _, objToPrint := range objsToPrint {
|
||||
if isFiltered, err := filterFuncs.Filter(objToPrint, filterOpts); !isFiltered {
|
||||
if err != nil {
|
||||
glog.V(2).Infof("Unable to filter resource: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if o.IsHumanReadablePrinter {
|
||||
// printing always takes the internal version, but the watch event uses externals
|
||||
// TODO fix printing to use server-side or be version agnostic
|
||||
internalGV := mapping.GroupVersionKind.GroupKind().WithVersion(runtime.APIVersionInternal).GroupVersion()
|
||||
if err := printer.PrintObj(attemptToConvertToInternal(objToPrint, mapping, internalGV), writer); err != nil {
|
||||
return fmt.Errorf("unable to output the provided object: %v", err)
|
||||
}
|
||||
objToPrint = attemptToConvertToInternal(objToPrint, legacyscheme.Scheme, internalGV)
|
||||
}
|
||||
if err := printer.PrintObj(objToPrint, writer); err != nil {
|
||||
return fmt.Errorf("unable to output the provided object: %v", err)
|
||||
}
|
||||
}
|
||||
writer.Flush()
|
||||
@ -618,18 +583,11 @@ func (options *GetOptions) watch(f cmdutil.Factory, cmd *cobra.Command, args []s
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if isFiltered, err := filterFuncs.Filter(e.Object, filterOpts); !isFiltered {
|
||||
if err != nil {
|
||||
glog.V(2).Infof("Unable to filter resource: %v", err)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// printing always takes the internal version, but the watch event uses externals
|
||||
// TODO fix printing to use server-side or be version agnostic
|
||||
internalGV := mapping.GroupVersionKind.GroupKind().WithVersion(runtime.APIVersionInternal).GroupVersion()
|
||||
if err := printer.PrintObj(attemptToConvertToInternal(e.Object, mapping, internalGV), options.Out); err != nil {
|
||||
return false, err
|
||||
}
|
||||
// printing always takes the internal version, but the watch event uses externals
|
||||
// TODO fix printing to use server-side or be version agnostic
|
||||
internalGV := mapping.GroupVersionKind.GroupKind().WithVersion(runtime.APIVersionInternal).GroupVersion()
|
||||
if err := printer.PrintObj(attemptToConvertToInternal(e.Object, legacyscheme.Scheme, internalGV), o.Out); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
@ -648,26 +606,36 @@ func attemptToConvertToInternal(obj runtime.Object, converter runtime.ObjectConv
|
||||
return internalObject
|
||||
}
|
||||
|
||||
func (options *GetOptions) decodeIntoTable(encoder runtime.Encoder, obj runtime.Object) (runtime.Object, error) {
|
||||
func (o *GetOptions) decodeIntoTable(obj runtime.Object) (runtime.Object, error) {
|
||||
if obj.GetObjectKind().GroupVersionKind().Kind != "Table" {
|
||||
return nil, fmt.Errorf("attempt to decode non-Table object into a v1beta1.Table")
|
||||
}
|
||||
|
||||
b, err := runtime.Encode(encoder, obj)
|
||||
if err != nil {
|
||||
unstr, ok := obj.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("attempt to decode non-Unstructured object")
|
||||
}
|
||||
table := &metav1beta1.Table{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstr.Object, table); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
table := &metav1beta1.Table{}
|
||||
err = json.Unmarshal(b, table)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
for i := range table.Rows {
|
||||
row := &table.Rows[i]
|
||||
if row.Object.Raw == nil || row.Object.Object != nil {
|
||||
continue
|
||||
}
|
||||
converted, err := runtime.Decode(unstructured.UnstructuredJSONScheme, row.Object.Raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
row.Object.Object = converted
|
||||
}
|
||||
|
||||
return table, nil
|
||||
}
|
||||
|
||||
func (options *GetOptions) printGeneric(printer printers.ResourcePrinter, r *resource.Result, filterFuncs kubectl.Filters, filterOpts *printers.PrintOptions) error {
|
||||
func (o *GetOptions) printGeneric(r *resource.Result) error {
|
||||
// we flattened the data from the builder, so we have individual items, but now we'd like to either:
|
||||
// 1. if there is more than one item, combine them all into a single list
|
||||
// 2. if there is a single item and that item is a list, leave it as its specific list
|
||||
@ -682,10 +650,15 @@ func (options *GetOptions) printGeneric(printer printers.ResourcePrinter, r *res
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
if len(infos) == 0 && options.IgnoreNotFound {
|
||||
if len(infos) == 0 && o.IgnoreNotFound {
|
||||
return utilerrors.Reduce(utilerrors.Flatten(utilerrors.NewAggregate(errs)))
|
||||
}
|
||||
|
||||
printer, err := o.ToPrinter(nil, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var obj runtime.Object
|
||||
if !singleItemImplied || len(infos) > 1 {
|
||||
// we have more than one item, so coerce all items into a list.
|
||||
@ -720,12 +693,12 @@ func (options *GetOptions) printGeneric(printer printers.ResourcePrinter, r *res
|
||||
|
||||
isList := meta.IsListType(obj)
|
||||
if isList {
|
||||
_, items, err := cmdutil.FilterResourceList(obj, filterFuncs, filterOpts)
|
||||
items, err := meta.ExtractList(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// take the filtered items and create a new list for display
|
||||
// take the items and create a new list for display
|
||||
list := &unstructured.UnstructuredList{
|
||||
Object: map[string]interface{}{
|
||||
"kind": "List",
|
||||
@ -743,29 +716,25 @@ func (options *GetOptions) printGeneric(printer printers.ResourcePrinter, r *res
|
||||
for _, item := range items {
|
||||
list.Items = append(list.Items, *item.(*unstructured.Unstructured))
|
||||
}
|
||||
if err := printer.PrintObj(list, options.Out); err != nil {
|
||||
if err := printer.PrintObj(list, o.Out); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return utilerrors.Reduce(utilerrors.Flatten(utilerrors.NewAggregate(errs)))
|
||||
}
|
||||
|
||||
if isFiltered, err := filterFuncs.Filter(obj, filterOpts); !isFiltered {
|
||||
if err != nil {
|
||||
glog.V(2).Infof("Unable to filter resource: %v", err)
|
||||
} else if err := printer.PrintObj(obj, options.Out); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if printErr := printer.PrintObj(obj, o.Out); printErr != nil {
|
||||
errs = append(errs, printErr)
|
||||
}
|
||||
|
||||
return utilerrors.Reduce(utilerrors.Flatten(utilerrors.NewAggregate(errs)))
|
||||
}
|
||||
|
||||
func addOpenAPIPrintColumnFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().Bool(useOpenAPIPrintColumnFlagLabel, true, "If true, use x-kubernetes-print-column metadata (if present) from the OpenAPI schema for displaying a resource.")
|
||||
func addOpenAPIPrintColumnFlags(cmd *cobra.Command, opt *GetOptions) {
|
||||
cmd.Flags().BoolVar(&opt.PrintWithOpenAPICols, useOpenAPIPrintColumnFlagLabel, opt.PrintWithOpenAPICols, "If true, use x-kubernetes-print-column metadata (if present) from the OpenAPI schema for displaying a resource.")
|
||||
}
|
||||
|
||||
func addServerPrintColumnFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().Bool(useServerPrintColumns, false, "If true, have the server return the appropriate table output. Supports extension APIs and CRD. Experimental.")
|
||||
func addServerPrintColumnFlags(cmd *cobra.Command, opt *GetOptions) {
|
||||
cmd.Flags().BoolVar(&opt.ServerPrint, useServerPrintColumns, opt.ServerPrint, "If true, have the server return the appropriate table output. Supports extension APIs and CRDs.")
|
||||
}
|
||||
|
||||
func shouldGetNewPrinterForMapping(printer printers.ResourcePrinter, lastMapping, mapping *meta.RESTMapping) bool {
|
||||
@ -776,46 +745,12 @@ func cmdSpecifiesOutputFmt(cmd *cobra.Command) bool {
|
||||
return cmdutil.GetFlagString(cmd, "output") != ""
|
||||
}
|
||||
|
||||
// outputOptsForMappingFromOpenAPI looks for the output format metatadata in the
|
||||
// openapi schema and modifies the passed print options for the mapping if found.
|
||||
func updatePrintOptionsForOpenAPI(f cmdutil.Factory, mapping *meta.RESTMapping, printOpts *printers.PrintOptions) bool {
|
||||
|
||||
// user has not specified any output format, check if OpenAPI has
|
||||
// default specification to print this resource type
|
||||
api, err := f.OpenAPISchema()
|
||||
if err != nil {
|
||||
// Error getting schema
|
||||
return false
|
||||
func maybeWrapSortingPrinter(printer printers.ResourcePrinter, sortBy string) printers.ResourcePrinter {
|
||||
if len(sortBy) != 0 {
|
||||
return &kubectl.SortingPrinter{
|
||||
Delegate: printer,
|
||||
SortField: fmt.Sprintf("%s", sortBy),
|
||||
}
|
||||
}
|
||||
// Found openapi metadata for this resource
|
||||
schema := api.LookupResource(mapping.GroupVersionKind)
|
||||
if schema == nil {
|
||||
// Schema not found, return empty columns
|
||||
return false
|
||||
}
|
||||
|
||||
columns, found := openapi.GetPrintColumns(schema.GetExtensions())
|
||||
if !found {
|
||||
// Extension not found, return empty columns
|
||||
return false
|
||||
}
|
||||
|
||||
return outputOptsFromStr(columns, printOpts)
|
||||
}
|
||||
|
||||
// outputOptsFromStr parses the print-column metadata and generates printer.OutputOptions object.
|
||||
func outputOptsFromStr(columnStr string, printOpts *printers.PrintOptions) bool {
|
||||
if columnStr == "" {
|
||||
return false
|
||||
}
|
||||
parts := strings.SplitN(columnStr, "=", 2)
|
||||
if len(parts) < 2 {
|
||||
return false
|
||||
}
|
||||
|
||||
printOpts.OutputFormatType = parts[0]
|
||||
printOpts.OutputFormatArgument = parts[1]
|
||||
printOpts.AllowMissingKeys = true
|
||||
|
||||
return true
|
||||
return printer
|
||||
}
|
190
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/get/get_flags.go
generated
vendored
Normal file
190
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/get/get_flags.go
generated
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
Copyright 2018 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 get
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
// PrintFlags composes common printer flag structs
|
||||
// used in the Get command.
|
||||
type PrintFlags struct {
|
||||
JSONYamlPrintFlags *genericclioptions.JSONYamlPrintFlags
|
||||
NamePrintFlags *genericclioptions.NamePrintFlags
|
||||
CustomColumnsFlags *printers.CustomColumnsPrintFlags
|
||||
HumanReadableFlags *HumanPrintFlags
|
||||
TemplateFlags *genericclioptions.KubeTemplatePrintFlags
|
||||
|
||||
NoHeaders *bool
|
||||
OutputFormat *string
|
||||
}
|
||||
|
||||
// SetKind sets the Kind option of humanreadable flags
|
||||
func (f *PrintFlags) SetKind(kind schema.GroupKind) {
|
||||
f.HumanReadableFlags.SetKind(kind)
|
||||
}
|
||||
|
||||
// EnsureWithNamespace ensures that humanreadable flags return
|
||||
// a printer capable of printing with a "namespace" column.
|
||||
func (f *PrintFlags) EnsureWithNamespace() error {
|
||||
return f.HumanReadableFlags.EnsureWithNamespace()
|
||||
}
|
||||
|
||||
// EnsureWithKind ensures that humanreadable flags return
|
||||
// a printer capable of including resource kinds.
|
||||
func (f *PrintFlags) EnsureWithKind() error {
|
||||
return f.HumanReadableFlags.EnsureWithKind()
|
||||
}
|
||||
|
||||
// Copy returns a copy of PrintFlags for mutation
|
||||
func (f *PrintFlags) Copy() PrintFlags {
|
||||
printFlags := *f
|
||||
return printFlags
|
||||
}
|
||||
|
||||
func (f *PrintFlags) AllowedFormats() []string {
|
||||
formats := f.JSONYamlPrintFlags.AllowedFormats()
|
||||
formats = append(formats, f.NamePrintFlags.AllowedFormats()...)
|
||||
formats = append(formats, f.TemplateFlags.AllowedFormats()...)
|
||||
formats = append(formats, f.CustomColumnsFlags.AllowedFormats()...)
|
||||
formats = append(formats, f.HumanReadableFlags.AllowedFormats()...)
|
||||
return formats
|
||||
}
|
||||
|
||||
// UseOpenAPIColumns modifies the output format, as well as the
|
||||
// "allowMissingKeys" option for template printers, to values
|
||||
// defined in the OpenAPI schema of a resource.
|
||||
func (f *PrintFlags) UseOpenAPIColumns(api openapi.Resources, mapping *meta.RESTMapping) error {
|
||||
// Found openapi metadata for this resource
|
||||
schema := api.LookupResource(mapping.GroupVersionKind)
|
||||
if schema == nil {
|
||||
// Schema not found, return empty columns
|
||||
return nil
|
||||
}
|
||||
|
||||
columns, found := openapi.GetPrintColumns(schema.GetExtensions())
|
||||
if !found {
|
||||
// Extension not found, return empty columns
|
||||
return nil
|
||||
}
|
||||
|
||||
parts := strings.SplitN(columns, "=", 2)
|
||||
if len(parts) < 2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
allowMissingKeys := true
|
||||
f.OutputFormat = &parts[0]
|
||||
f.TemplateFlags.TemplateArgument = &parts[1]
|
||||
f.TemplateFlags.AllowMissingKeys = &allowMissingKeys
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToPrinter attempts to find a composed set of PrintFlags suitable for
|
||||
// returning a printer based on current flag values.
|
||||
func (f *PrintFlags) ToPrinter() (printers.ResourcePrinter, error) {
|
||||
outputFormat := ""
|
||||
if f.OutputFormat != nil {
|
||||
outputFormat = *f.OutputFormat
|
||||
}
|
||||
|
||||
noHeaders := false
|
||||
if f.NoHeaders != nil {
|
||||
noHeaders = *f.NoHeaders
|
||||
}
|
||||
f.HumanReadableFlags.NoHeaders = noHeaders
|
||||
f.CustomColumnsFlags.NoHeaders = noHeaders
|
||||
|
||||
// for "get.go" we want to support a --template argument given, even when no --output format is provided
|
||||
if f.TemplateFlags.TemplateArgument != nil && len(*f.TemplateFlags.TemplateArgument) > 0 && len(outputFormat) == 0 {
|
||||
outputFormat = "go-template"
|
||||
}
|
||||
|
||||
if p, err := f.TemplateFlags.ToPrinter(outputFormat); !genericclioptions.IsNoCompatiblePrinterError(err) {
|
||||
return p, err
|
||||
}
|
||||
|
||||
if f.TemplateFlags.TemplateArgument != nil {
|
||||
f.CustomColumnsFlags.TemplateArgument = *f.TemplateFlags.TemplateArgument
|
||||
}
|
||||
|
||||
if p, err := f.JSONYamlPrintFlags.ToPrinter(outputFormat); !genericclioptions.IsNoCompatiblePrinterError(err) {
|
||||
return p, err
|
||||
}
|
||||
|
||||
if p, err := f.HumanReadableFlags.ToPrinter(outputFormat); !genericclioptions.IsNoCompatiblePrinterError(err) {
|
||||
return p, err
|
||||
}
|
||||
|
||||
if p, err := f.CustomColumnsFlags.ToPrinter(outputFormat); !genericclioptions.IsNoCompatiblePrinterError(err) {
|
||||
return p, err
|
||||
}
|
||||
|
||||
if p, err := f.NamePrintFlags.ToPrinter(outputFormat); !genericclioptions.IsNoCompatiblePrinterError(err) {
|
||||
return p, err
|
||||
}
|
||||
|
||||
return nil, genericclioptions.NoCompatiblePrinterError{OutputFormat: &outputFormat, AllowedFormats: f.AllowedFormats()}
|
||||
}
|
||||
|
||||
// AddFlags receives a *cobra.Command reference and binds
|
||||
// flags related to humanreadable and template printing.
|
||||
func (f *PrintFlags) AddFlags(cmd *cobra.Command) {
|
||||
f.JSONYamlPrintFlags.AddFlags(cmd)
|
||||
f.NamePrintFlags.AddFlags(cmd)
|
||||
f.TemplateFlags.AddFlags(cmd)
|
||||
f.HumanReadableFlags.AddFlags(cmd)
|
||||
f.CustomColumnsFlags.AddFlags(cmd)
|
||||
|
||||
if f.OutputFormat != nil {
|
||||
cmd.Flags().StringVarP(f.OutputFormat, "output", "o", *f.OutputFormat, "Output format. One of: json|yaml|wide|name|custom-columns=...|custom-columns-file=...|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See custom columns [http://kubernetes.io/docs/user-guide/kubectl-overview/#custom-columns], golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://kubernetes.io/docs/user-guide/jsonpath].")
|
||||
}
|
||||
if f.NoHeaders != nil {
|
||||
cmd.Flags().BoolVar(f.NoHeaders, "no-headers", *f.NoHeaders, "When using the default or custom-column output format, don't print headers (default print headers).")
|
||||
}
|
||||
|
||||
// TODO(juanvallejo): This is deprecated - remove
|
||||
cmd.Flags().BoolP("show-all", "a", true, "When printing, show all resources (default show all pods including terminated one.)")
|
||||
cmd.Flags().MarkDeprecated("show-all", "will be removed in an upcoming release")
|
||||
}
|
||||
|
||||
// NewGetPrintFlags returns flags associated with humanreadable,
|
||||
// template, and "name" printing, with default values set.
|
||||
func NewGetPrintFlags() *PrintFlags {
|
||||
outputFormat := ""
|
||||
noHeaders := false
|
||||
|
||||
return &PrintFlags{
|
||||
OutputFormat: &outputFormat,
|
||||
NoHeaders: &noHeaders,
|
||||
|
||||
JSONYamlPrintFlags: genericclioptions.NewJSONYamlPrintFlags(),
|
||||
NamePrintFlags: genericclioptions.NewNamePrintFlags(""),
|
||||
TemplateFlags: genericclioptions.NewKubeTemplatePrintFlags(),
|
||||
|
||||
HumanReadableFlags: NewHumanPrintFlags(),
|
||||
CustomColumnsFlags: printers.NewCustomColumnsPrintFlags(),
|
||||
}
|
||||
}
|
@ -14,12 +14,11 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resource
|
||||
package get
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
encjson "encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@ -28,29 +27,28 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/dynamic"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
restclientwatch "k8s.io/client-go/rest/watch"
|
||||
"k8s.io/kube-openapi/pkg/util/proto"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/core/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
openapitesting "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
@ -63,7 +61,7 @@ func init() {
|
||||
scheme.Scheme.AddConversionFuncs(v1.Convert_v1_PodSecurityContext_To_core_PodSecurityContext)
|
||||
}
|
||||
|
||||
var unstructuredSerializer = dynamic.ContentConfig().NegotiatedSerializer
|
||||
var unstructuredSerializer = resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer
|
||||
|
||||
func defaultHeader() http.Header {
|
||||
header := http.Header{}
|
||||
@ -77,36 +75,11 @@ func defaultClientConfig() *restclient.Config {
|
||||
ContentConfig: restclient.ContentConfig{
|
||||
NegotiatedSerializer: scheme.Codecs,
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
GroupVersion: &scheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
|
||||
GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type testPrinter struct {
|
||||
Objects []runtime.Object
|
||||
Err error
|
||||
GenericPrinter bool
|
||||
}
|
||||
|
||||
func (t *testPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
|
||||
t.Objects = append(t.Objects, obj)
|
||||
fmt.Fprintf(out, "%#v", obj)
|
||||
return t.Err
|
||||
}
|
||||
|
||||
// TODO: implement HandledResources()
|
||||
func (t *testPrinter) HandledResources() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (t *testPrinter) AfterPrint(output io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *testPrinter) IsGeneric() bool {
|
||||
return t.GenericPrinter
|
||||
}
|
||||
|
||||
func objBody(codec runtime.Codec, obj runtime.Object) io.ReadCloser {
|
||||
return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, obj))))
|
||||
}
|
||||
@ -129,11 +102,11 @@ func testData() (*api.PodList, *api.ServiceList, *api.ReplicationControllerList)
|
||||
Items: []api.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "10"},
|
||||
Spec: apitesting.DeepEqualSafePodSpec(),
|
||||
Spec: apitesting.V1DeepEqualSafePodSpec(),
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "bar", Namespace: "test", ResourceVersion: "11"},
|
||||
Spec: apitesting.DeepEqualSafePodSpec(),
|
||||
Spec: apitesting.V1DeepEqualSafePodSpec(),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -151,6 +124,8 @@ func testData() (*api.PodList, *api.ServiceList, *api.ReplicationControllerList)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
one := int32(1)
|
||||
rc := &api.ReplicationControllerList{
|
||||
ListMeta: metav1.ListMeta{
|
||||
ResourceVersion: "17",
|
||||
@ -159,7 +134,7 @@ func testData() (*api.PodList, *api.ServiceList, *api.ReplicationControllerList)
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "rc1", Namespace: "test", ResourceVersion: "18"},
|
||||
Spec: api.ReplicationControllerSpec{
|
||||
Replicas: 1,
|
||||
Replicas: &one,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -197,7 +172,8 @@ func testComponentStatusData() *api.ComponentStatusList {
|
||||
// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
|
||||
func TestGetUnknownSchemaObject(t *testing.T) {
|
||||
t.Skip("This test is completely broken. The first thing it does is add the object to the scheme!")
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
_, _, codec := cmdtesting.NewExternalScheme()
|
||||
tf.OpenAPISchemaFunc = openapitesting.CreateOpenAPISchemaFunc(openapiSchemaPath)
|
||||
|
||||
@ -214,38 +190,15 @@ func TestGetUnknownSchemaObject(t *testing.T) {
|
||||
Body: objBody(codec, obj),
|
||||
},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
mapper, _ := tf.Object()
|
||||
m, err := mapper.RESTMapping(schema.GroupKind{Group: "apitest", Kind: "Type"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
convertedObj, err := m.ConvertToVersion(&unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"kind": "Type",
|
||||
"apiVersion": "apitest/unlikelyversion",
|
||||
"name": "foo",
|
||||
},
|
||||
}, schema.GroupVersion{Group: "apitest", Version: "unlikelyversion"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(convertedObj, obj) {
|
||||
t.Fatalf("unexpected conversion of unstructured object to structured: %s", diff.ObjectReflectDiff(convertedObj, obj))
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Run(cmd, []string{"type", "foo"})
|
||||
|
||||
expected := []runtime.Object{cmdtesting.NewInternalType("", "", "foo")}
|
||||
actual := []runtime.Object{}
|
||||
//actual := tf.Printer.(*testPrinter).Objects
|
||||
if len(actual) != len(expected) {
|
||||
t.Fatalf("expected: %#v, but actual: %#v", expected, actual)
|
||||
}
|
||||
@ -271,18 +224,19 @@ func TestGetUnknownSchemaObject(t *testing.T) {
|
||||
|
||||
// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
|
||||
func TestGetSchemaObject(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := testapi.Default.Codec()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(schema.GroupVersion{Version: "v1"})
|
||||
t.Logf("%v", string(runtime.EncodeOrDie(codec, &api.ReplicationController{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})))
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &api.ReplicationController{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.Run(cmd, []string{"replicationcontrollers", "foo"})
|
||||
|
||||
if !strings.Contains(buf.String(), "foo") {
|
||||
@ -293,8 +247,9 @@ func TestGetSchemaObject(t *testing.T) {
|
||||
func TestGetObjectsWithOpenAPIOutputFormatPresent(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
// overide the openAPISchema function to return custom output
|
||||
// for Pod type.
|
||||
@ -303,11 +258,9 @@ func TestGetObjectsWithOpenAPIOutputFormatPresent(t *testing.T) {
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Flags().Set(useOpenAPIPrintColumnFlagLabel, "true")
|
||||
cmd.Run(cmd, []string{"pods", "foo"})
|
||||
@ -350,18 +303,17 @@ func testOpenAPISchemaData() (openapi.Resources, error) {
|
||||
func TestGetObjects(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Run(cmd, []string{"pods", "foo"})
|
||||
|
||||
@ -373,72 +325,55 @@ foo 0/0 0 <unknown>
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetObjectsFiltered(t *testing.T) {
|
||||
initTestErrorHandler(t)
|
||||
|
||||
func TestGetObjectsShowKind(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
pods.Items[0].Status.Phase = api.PodFailed
|
||||
first := &pods.Items[0]
|
||||
|
||||
testCases := []struct {
|
||||
args []string
|
||||
resp runtime.Object
|
||||
flags map[string]string
|
||||
expect string
|
||||
}{
|
||||
{args: []string{"pods", "foo"}, resp: first, flags: map[string]string{"show-all": "true"},
|
||||
expect: "NAME READY STATUS RESTARTS AGE\nfoo 0/0 Failed 0 <unknown>\n"},
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
{args: []string{"pods", "foo"}, flags: map[string]string{"show-all": "false"}, resp: first,
|
||||
expect: "NAME READY STATUS RESTARTS AGE\nfoo 0/0 Failed 0 <unknown>\n"},
|
||||
|
||||
{args: []string{"pods"}, flags: map[string]string{"show-all": "true"}, resp: pods,
|
||||
expect: "NAME READY STATUS RESTARTS AGE\nfoo 0/0 Failed 0 <unknown>\nbar 0/0 0 <unknown>\n"},
|
||||
|
||||
{args: []string{"pods/foo"}, resp: first, flags: map[string]string{"show-all": "false"},
|
||||
expect: "NAME READY STATUS RESTARTS AGE\nfoo 0/0 Failed 0 <unknown>\n"},
|
||||
|
||||
{args: []string{"pods"}, flags: map[string]string{"show-all": "false", "output": "name"}, resp: pods,
|
||||
expect: "pod/foo\npod/bar\n"},
|
||||
|
||||
{args: []string{}, flags: map[string]string{"show-all": "false", "filename": "../../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}, resp: pods,
|
||||
expect: "NAME READY STATUS RESTARTS AGE\nfoo 0/0 Failed 0 <unknown>\nbar 0/0 0 <unknown>\n"},
|
||||
|
||||
{args: []string{"pods"}, resp: pods, flags: map[string]string{"show-all": "false"},
|
||||
expect: "NAME READY STATUS RESTARTS AGE\nbar 0/0 0 <unknown>\n"},
|
||||
|
||||
{args: []string{"pods"}, flags: map[string]string{"show-all": "true", "output": "name"}, resp: pods,
|
||||
expect: "pod/foo\npod/bar\n"},
|
||||
|
||||
{args: []string{"pods"}, flags: map[string]string{"show-all": "false"}, resp: pods,
|
||||
expect: "NAME READY STATUS RESTARTS AGE\nbar 0/0 0 <unknown>\n"},
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])},
|
||||
}
|
||||
|
||||
for i, test := range testCases {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Flags().Set("show-kind", "true")
|
||||
cmd.Run(cmd, []string{"pods", "foo"})
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
GroupVersion: schema.GroupVersion{Version: "v1"},
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, test.resp)},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
expected := `NAME READY STATUS RESTARTS AGE
|
||||
pod/foo 0/0 0 <unknown>
|
||||
`
|
||||
if e, a := expected, buf.String(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
cmd.SetOutput(buf)
|
||||
for k, v := range test.flags {
|
||||
cmd.Flags().Lookup(k).Value.Set(v)
|
||||
}
|
||||
cmd.Run(cmd, test.args)
|
||||
func TestGetObjectsShowLabels(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
if e, a := test.expect, buf.String(); e != a {
|
||||
t.Errorf("expected %q, got %q", e, a)
|
||||
}
|
||||
})
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])},
|
||||
}
|
||||
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Flags().Set("show-labels", "true")
|
||||
cmd.Run(cmd, []string{"pods", "foo"})
|
||||
|
||||
expected := `NAME READY STATUS RESTARTS AGE LABELS
|
||||
foo 0/0 0 <unknown> <none>
|
||||
`
|
||||
if e, a := expected, buf.String(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
@ -457,8 +392,9 @@ func TestGetObjectIgnoreNotFound(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -474,11 +410,9 @@ func TestGetObjectIgnoreNotFound(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Flags().Set("ignore-not-found", "true")
|
||||
cmd.Flags().Set("output", "yaml")
|
||||
@ -497,33 +431,31 @@ func TestGetSortedObjects(t *testing.T) {
|
||||
Items: []api.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "c", Namespace: "test", ResourceVersion: "10"},
|
||||
Spec: apitesting.DeepEqualSafePodSpec(),
|
||||
Spec: apitesting.V1DeepEqualSafePodSpec(),
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "b", Namespace: "test", ResourceVersion: "11"},
|
||||
Spec: apitesting.DeepEqualSafePodSpec(),
|
||||
Spec: apitesting.V1DeepEqualSafePodSpec(),
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "a", Namespace: "test", ResourceVersion: "9"},
|
||||
Spec: apitesting.DeepEqualSafePodSpec(),
|
||||
Spec: apitesting.V1DeepEqualSafePodSpec(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: "v1"}}}
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
|
||||
// sorting with metedata.name
|
||||
@ -543,18 +475,17 @@ c 0/0 0 <unknown>
|
||||
func TestGetObjectsIdentifiedByFile(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Flags().Set("filename", "../../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml")
|
||||
cmd.Run(cmd, []string{})
|
||||
@ -570,18 +501,17 @@ foo 0/0 0 <unknown>
|
||||
func TestGetListObjects(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Run(cmd, []string{"pods"})
|
||||
|
||||
@ -594,49 +524,20 @@ bar 0/0 0 <unknown>
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAllListObjects(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Flags().Set("show-all", "true")
|
||||
cmd.Run(cmd, []string{"pods"})
|
||||
|
||||
expected := `NAME READY STATUS RESTARTS AGE
|
||||
foo 0/0 0 <unknown>
|
||||
bar 0/0 0 <unknown>
|
||||
`
|
||||
if e, a := expected, buf.String(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetListComponentStatus(t *testing.T) {
|
||||
statuses := testComponentStatusData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, statuses)},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Run(cmd, []string{"componentstatuses"})
|
||||
|
||||
@ -666,8 +567,9 @@ func TestGetMixedGenericObjects(t *testing.T) {
|
||||
Code: 0,
|
||||
}
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -681,12 +583,10 @@ func TestGetMixedGenericObjects(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Flags().Set("output", "json")
|
||||
cmd.Run(cmd, []string{"pods"})
|
||||
@ -716,8 +616,9 @@ func TestGetMixedGenericObjects(t *testing.T) {
|
||||
func TestGetMultipleTypeObjects(t *testing.T) {
|
||||
pods, svc, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -733,19 +634,17 @@ func TestGetMultipleTypeObjects(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Run(cmd, []string{"pods,services"})
|
||||
|
||||
expected := `NAME READY STATUS RESTARTS AGE
|
||||
foo 0/0 0 <unknown>
|
||||
bar 0/0 0 <unknown>
|
||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
baz ClusterIP <none> <none> <none> <unknown>
|
||||
pod/foo 0/0 0 <unknown>
|
||||
pod/bar 0/0 0 <unknown>
|
||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
service/baz ClusterIP <none> <none> <none> <unknown>
|
||||
`
|
||||
if e, a := expected, buf.String(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
@ -755,8 +654,9 @@ baz ClusterIP <none> <none> <none> <unknown>
|
||||
func TestGetMultipleTypeObjectsAsList(t *testing.T) {
|
||||
pods, svc, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -772,12 +672,10 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
|
||||
cmd.Flags().Set("output", "json")
|
||||
@ -799,7 +697,6 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
|
||||
"containers": null,
|
||||
"dnsPolicy": "ClusterFirst",
|
||||
"restartPolicy": "Always",
|
||||
"schedulerName": "default-scheduler",
|
||||
"securityContext": {},
|
||||
"terminationGracePeriodSeconds": 30
|
||||
},
|
||||
@ -818,7 +715,6 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
|
||||
"containers": null,
|
||||
"dnsPolicy": "ClusterFirst",
|
||||
"restartPolicy": "Always",
|
||||
"schedulerName": "default-scheduler",
|
||||
"securityContext": {},
|
||||
"terminationGracePeriodSeconds": 30
|
||||
},
|
||||
@ -850,15 +746,16 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
|
||||
}
|
||||
`
|
||||
if e, a := expected, buf.String(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
t.Errorf("did not match: %v", diff.StringDiff(e, a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMultipleTypeObjectsWithLabelSelector(t *testing.T) {
|
||||
pods, svc, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -877,21 +774,19 @@ func TestGetMultipleTypeObjectsWithLabelSelector(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
|
||||
cmd.Flags().Set("selector", "a=b")
|
||||
cmd.Run(cmd, []string{"pods,services"})
|
||||
|
||||
expected := `NAME READY STATUS RESTARTS AGE
|
||||
foo 0/0 0 <unknown>
|
||||
bar 0/0 0 <unknown>
|
||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
baz ClusterIP <none> <none> <none> <unknown>
|
||||
pod/foo 0/0 0 <unknown>
|
||||
pod/bar 0/0 0 <unknown>
|
||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
service/baz ClusterIP <none> <none> <none> <unknown>
|
||||
`
|
||||
if e, a := expected, buf.String(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
@ -901,8 +796,9 @@ baz ClusterIP <none> <none> <none> <unknown>
|
||||
func TestGetMultipleTypeObjectsWithFieldSelector(t *testing.T) {
|
||||
pods, svc, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -921,21 +817,19 @@ func TestGetMultipleTypeObjectsWithFieldSelector(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
|
||||
cmd.Flags().Set("field-selector", "a=b")
|
||||
cmd.Run(cmd, []string{"pods,services"})
|
||||
|
||||
expected := `NAME READY STATUS RESTARTS AGE
|
||||
foo 0/0 0 <unknown>
|
||||
bar 0/0 0 <unknown>
|
||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
baz ClusterIP <none> <none> <none> <unknown>
|
||||
pod/foo 0/0 0 <unknown>
|
||||
pod/bar 0/0 0 <unknown>
|
||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
service/baz ClusterIP <none> <none> <none> <unknown>
|
||||
`
|
||||
if e, a := expected, buf.String(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
@ -948,13 +842,11 @@ func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
ExternalID: "ext",
|
||||
},
|
||||
}
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -970,51 +862,23 @@ func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
|
||||
cmd.Run(cmd, []string{"services/bar", "node/foo"})
|
||||
|
||||
expected := `NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
baz ClusterIP <none> <none> <none> <unknown>
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
foo Unknown <none> <unknown>
|
||||
expected := `NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
service/baz ClusterIP <none> <none> <none> <unknown>
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
node/foo Unknown <none> <unknown>
|
||||
`
|
||||
if e, a := expected, buf.String(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetByFormatForcesFlag(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Flags().Lookup("output").Value.Set("yaml")
|
||||
cmd.Flags().Set("show-all", "false")
|
||||
cmd.Run(cmd, []string{"pods"})
|
||||
|
||||
showAllFlag, _ := cmd.Flags().GetBool("show-all")
|
||||
if showAllFlag {
|
||||
t.Error("expected showAll to not be true when getting resource")
|
||||
}
|
||||
}
|
||||
|
||||
func watchTestData() ([]api.Pod, []watch.Event) {
|
||||
pods := []api.Pod{
|
||||
{
|
||||
@ -1023,7 +887,7 @@ func watchTestData() ([]api.Pod, []watch.Event) {
|
||||
Namespace: "test",
|
||||
ResourceVersion: "9",
|
||||
},
|
||||
Spec: apitesting.DeepEqualSafePodSpec(),
|
||||
Spec: apitesting.V1DeepEqualSafePodSpec(),
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@ -1031,7 +895,7 @@ func watchTestData() ([]api.Pod, []watch.Event) {
|
||||
Namespace: "test",
|
||||
ResourceVersion: "10",
|
||||
},
|
||||
Spec: apitesting.DeepEqualSafePodSpec(),
|
||||
Spec: apitesting.V1DeepEqualSafePodSpec(),
|
||||
},
|
||||
}
|
||||
events := []watch.Event{
|
||||
@ -1044,7 +908,7 @@ func watchTestData() ([]api.Pod, []watch.Event) {
|
||||
Namespace: "test",
|
||||
ResourceVersion: "9",
|
||||
},
|
||||
Spec: apitesting.DeepEqualSafePodSpec(),
|
||||
Spec: apitesting.V1DeepEqualSafePodSpec(),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1055,7 +919,7 @@ func watchTestData() ([]api.Pod, []watch.Event) {
|
||||
Namespace: "test",
|
||||
ResourceVersion: "10",
|
||||
},
|
||||
Spec: apitesting.DeepEqualSafePodSpec(),
|
||||
Spec: apitesting.V1DeepEqualSafePodSpec(),
|
||||
},
|
||||
},
|
||||
// resource events
|
||||
@ -1067,7 +931,7 @@ func watchTestData() ([]api.Pod, []watch.Event) {
|
||||
Namespace: "test",
|
||||
ResourceVersion: "11",
|
||||
},
|
||||
Spec: apitesting.DeepEqualSafePodSpec(),
|
||||
Spec: apitesting.V1DeepEqualSafePodSpec(),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1078,7 +942,7 @@ func watchTestData() ([]api.Pod, []watch.Event) {
|
||||
Namespace: "test",
|
||||
ResourceVersion: "12",
|
||||
},
|
||||
Spec: apitesting.DeepEqualSafePodSpec(),
|
||||
Spec: apitesting.V1DeepEqualSafePodSpec(),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -1088,8 +952,9 @@ func watchTestData() ([]api.Pod, []watch.Event) {
|
||||
func TestWatchLabelSelector(t *testing.T) {
|
||||
pods, events := watchTestData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
podList := &api.PodList{
|
||||
Items: pods,
|
||||
@ -1115,11 +980,9 @@ func TestWatchLabelSelector(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
|
||||
cmd.Flags().Set("watch", "true")
|
||||
@ -1140,8 +1003,9 @@ foo 0/0 0 <unknown>
|
||||
func TestWatchFieldSelector(t *testing.T) {
|
||||
pods, events := watchTestData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
podList := &api.PodList{
|
||||
Items: pods,
|
||||
@ -1167,11 +1031,9 @@ func TestWatchFieldSelector(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
|
||||
cmd.Flags().Set("watch", "true")
|
||||
@ -1192,8 +1054,9 @@ foo 0/0 0 <unknown>
|
||||
func TestWatchResource(t *testing.T) {
|
||||
pods, events := watchTestData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -1213,11 +1076,9 @@ func TestWatchResource(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
|
||||
cmd.Flags().Set("watch", "true")
|
||||
@ -1236,8 +1097,9 @@ foo 0/0 0 <unknown>
|
||||
func TestWatchResourceIdentifiedByFile(t *testing.T) {
|
||||
pods, events := watchTestData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -1257,11 +1119,9 @@ func TestWatchResourceIdentifiedByFile(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
|
||||
cmd.Flags().Set("watch", "true")
|
||||
@ -1281,8 +1141,9 @@ foo 0/0 0 <unknown>
|
||||
func TestWatchOnlyResource(t *testing.T) {
|
||||
pods, events := watchTestData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -1302,11 +1163,9 @@ func TestWatchOnlyResource(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
|
||||
cmd.Flags().Set("watch-only", "true")
|
||||
@ -1324,8 +1183,9 @@ foo 0/0 0 <unknown>
|
||||
func TestWatchOnlyList(t *testing.T) {
|
||||
pods, events := watchTestData()
|
||||
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
podList := &api.PodList{
|
||||
Items: pods,
|
||||
@ -1348,11 +1208,9 @@ func TestWatchOnlyList(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(tf, buf, errBuf)
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdGet("kubectl", tf, streams)
|
||||
cmd.SetOutput(buf)
|
||||
|
||||
cmd.Flags().Set("watch-only", "true")
|
144
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/get/humanreadable_flags.go
generated
vendored
Normal file
144
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/get/humanreadable_flags.go
generated
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
Copyright 2018 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 get
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||
)
|
||||
|
||||
// HumanPrintFlags provides default flags necessary for printing.
|
||||
// Given the following flag values, a printer can be requested that knows
|
||||
// how to handle printing based on these values.
|
||||
type HumanPrintFlags struct {
|
||||
ShowKind *bool
|
||||
ShowLabels *bool
|
||||
SortBy *string
|
||||
ColumnLabels *[]string
|
||||
|
||||
// get.go-specific values
|
||||
NoHeaders bool
|
||||
|
||||
Kind schema.GroupKind
|
||||
AbsoluteTimestamps bool
|
||||
WithNamespace bool
|
||||
}
|
||||
|
||||
// SetKind sets the Kind option
|
||||
func (f *HumanPrintFlags) SetKind(kind schema.GroupKind) {
|
||||
f.Kind = kind
|
||||
}
|
||||
|
||||
// EnsureWithKind sets the "Showkind" humanreadable option to true.
|
||||
func (f *HumanPrintFlags) EnsureWithKind() error {
|
||||
showKind := true
|
||||
f.ShowKind = &showKind
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureWithNamespace sets the "WithNamespace" humanreadable option to true.
|
||||
func (f *HumanPrintFlags) EnsureWithNamespace() error {
|
||||
f.WithNamespace = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *HumanPrintFlags) AllowedFormats() []string {
|
||||
return []string{"wide"}
|
||||
}
|
||||
|
||||
// ToPrinter receives an outputFormat and returns a printer capable of
|
||||
// handling human-readable output.
|
||||
func (f *HumanPrintFlags) ToPrinter(outputFormat string) (printers.ResourcePrinter, error) {
|
||||
if len(outputFormat) > 0 && outputFormat != "wide" {
|
||||
return nil, genericclioptions.NoCompatiblePrinterError{Options: f, AllowedFormats: f.AllowedFormats()}
|
||||
}
|
||||
|
||||
decoder := scheme.Codecs.UniversalDecoder()
|
||||
|
||||
showKind := false
|
||||
if f.ShowKind != nil {
|
||||
showKind = *f.ShowKind
|
||||
}
|
||||
|
||||
showLabels := false
|
||||
if f.ShowLabels != nil {
|
||||
showLabels = *f.ShowLabels
|
||||
}
|
||||
|
||||
columnLabels := []string{}
|
||||
if f.ColumnLabels != nil {
|
||||
columnLabels = *f.ColumnLabels
|
||||
}
|
||||
|
||||
p := printers.NewHumanReadablePrinter(decoder, printers.PrintOptions{
|
||||
Kind: f.Kind,
|
||||
WithKind: showKind,
|
||||
NoHeaders: f.NoHeaders,
|
||||
Wide: outputFormat == "wide",
|
||||
WithNamespace: f.WithNamespace,
|
||||
ColumnLabels: columnLabels,
|
||||
ShowLabels: showLabels,
|
||||
})
|
||||
printersinternal.AddHandlers(p)
|
||||
|
||||
// TODO(juanvallejo): handle sorting here
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// AddFlags receives a *cobra.Command reference and binds
|
||||
// flags related to human-readable printing to it
|
||||
func (f *HumanPrintFlags) AddFlags(c *cobra.Command) {
|
||||
if f.ShowLabels != nil {
|
||||
c.Flags().BoolVar(f.ShowLabels, "show-labels", *f.ShowLabels, "When printing, show all labels as the last column (default hide labels column)")
|
||||
}
|
||||
if f.SortBy != nil {
|
||||
c.Flags().StringVar(f.SortBy, "sort-by", *f.SortBy, "If non-empty, sort list types using this field specification. The field specification is expressed as a JSONPath expression (e.g. '{.metadata.name}'). The field in the API resource specified by this JSONPath expression must be an integer or a string.")
|
||||
}
|
||||
if f.ColumnLabels != nil {
|
||||
c.Flags().StringSliceVarP(f.ColumnLabels, "label-columns", "L", *f.ColumnLabels, "Accepts a comma separated list of labels that are going to be presented as columns. Names are case-sensitive. You can also use multiple flag options like -L label1 -L label2...")
|
||||
}
|
||||
if f.ShowKind != nil {
|
||||
c.Flags().BoolVar(f.ShowKind, "show-kind", *f.ShowKind, "If present, list the resource type for the requested object(s).")
|
||||
}
|
||||
}
|
||||
|
||||
// NewHumanPrintFlags returns flags associated with
|
||||
// human-readable printing, with default values set.
|
||||
func NewHumanPrintFlags() *HumanPrintFlags {
|
||||
showLabels := false
|
||||
sortBy := ""
|
||||
showKind := false
|
||||
columnLabels := []string{}
|
||||
|
||||
return &HumanPrintFlags{
|
||||
NoHeaders: false,
|
||||
WithNamespace: false,
|
||||
AbsoluteTimestamps: false,
|
||||
ColumnLabels: &columnLabels,
|
||||
|
||||
Kind: schema.GroupKind{},
|
||||
ShowLabels: &showLabels,
|
||||
SortBy: &sortBy,
|
||||
ShowKind: &showKind,
|
||||
}
|
||||
}
|
156
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/get/humanreadable_flags_test.go
generated
vendored
Normal file
156
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/get/humanreadable_flags_test.go
generated
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
Copyright 2018 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 get
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
func TestHumanReadablePrinterSupportsExpectedOptions(t *testing.T) {
|
||||
testObject := &api.Pod{ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Labels: map[string]string{
|
||||
"l1": "value",
|
||||
},
|
||||
}}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
showKind bool
|
||||
showLabels bool
|
||||
|
||||
// TODO(juanvallejo): test sorting once it's moved to the HumanReadablePrinter
|
||||
sortBy string
|
||||
columnLabels []string
|
||||
|
||||
noHeaders bool
|
||||
withNamespace bool
|
||||
|
||||
outputFormat string
|
||||
|
||||
expectedError string
|
||||
expectedOutput string
|
||||
expectNoMatch bool
|
||||
}{
|
||||
{
|
||||
name: "empty output format matches a humanreadable printer",
|
||||
expectedOutput: "NAME\\ +READY\\ +STATUS\\ +RESTARTS\\ +AGE\nfoo\\ +0/0\\ +0\\ +<unknown>\n",
|
||||
},
|
||||
{
|
||||
name: "\"wide\" output format prints",
|
||||
outputFormat: "wide",
|
||||
expectedOutput: "NAME\\ +READY\\ +STATUS\\ +RESTARTS\\ +AGE\\ +IP\\ +NODE\nfoo\\ +0/0\\ +0\\ +<unknown>\\ +<none>\\ +<none>\n",
|
||||
},
|
||||
{
|
||||
name: "no-headers prints output with no headers",
|
||||
noHeaders: true,
|
||||
expectedOutput: "foo\\ +0/0\\ +0\\ +<unknown>\n",
|
||||
},
|
||||
{
|
||||
name: "no-headers and a \"wide\" output format prints output with no headers and additional columns",
|
||||
outputFormat: "wide",
|
||||
noHeaders: true,
|
||||
expectedOutput: "foo\\ +0/0\\ +0\\ +<unknown>\\ +<none>\\ +<none>\n",
|
||||
},
|
||||
{
|
||||
name: "show-kind displays the resource's kind, even when printing a single type of resource",
|
||||
showKind: true,
|
||||
expectedOutput: "NAME\\ +READY\\ +STATUS\\ +RESTARTS\\ +AGE\npod/foo\\ +0/0\\ +0\\ +<unknown>\n",
|
||||
},
|
||||
{
|
||||
name: "label-columns prints specified label values in new column",
|
||||
columnLabels: []string{"l1"},
|
||||
expectedOutput: "NAME\\ +READY\\ +STATUS\\ +RESTARTS\\ +AGE\\ +L1\nfoo\\ +0/0\\ +0\\ +<unknown>\\ +value\n",
|
||||
},
|
||||
{
|
||||
name: "withNamespace displays an additional NAMESPACE column",
|
||||
withNamespace: true,
|
||||
expectedOutput: "NAMESPACE\\ +NAME\\ +READY\\ +STATUS\\ +RESTARTS\\ +AGE\n\\ +foo\\ +0/0\\ +0\\ +<unknown>\n",
|
||||
},
|
||||
{
|
||||
name: "no printer is matched on an invalid outputFormat",
|
||||
outputFormat: "invalid",
|
||||
expectNoMatch: true,
|
||||
},
|
||||
{
|
||||
name: "printer should not match on any other format supported by another printer",
|
||||
outputFormat: "go-template",
|
||||
expectNoMatch: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
printFlags := HumanPrintFlags{
|
||||
ShowKind: &tc.showKind,
|
||||
ShowLabels: &tc.showLabels,
|
||||
SortBy: &tc.sortBy,
|
||||
ColumnLabels: &tc.columnLabels,
|
||||
|
||||
NoHeaders: tc.noHeaders,
|
||||
WithNamespace: tc.withNamespace,
|
||||
}
|
||||
|
||||
if tc.showKind {
|
||||
printFlags.Kind = schema.GroupKind{Kind: "pod"}
|
||||
}
|
||||
|
||||
p, err := printFlags.ToPrinter(tc.outputFormat)
|
||||
if tc.expectNoMatch {
|
||||
if !genericclioptions.IsNoCompatiblePrinterError(err) {
|
||||
t.Fatalf("expected no printer matches for output format %q", tc.outputFormat)
|
||||
}
|
||||
return
|
||||
}
|
||||
if genericclioptions.IsNoCompatiblePrinterError(err) {
|
||||
t.Fatalf("expected to match template printer for output format %q", tc.outputFormat)
|
||||
}
|
||||
|
||||
if len(tc.expectedError) > 0 {
|
||||
if err == nil || !strings.Contains(err.Error(), tc.expectedError) {
|
||||
t.Errorf("expecting error %q, got %v", tc.expectedError, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
out := bytes.NewBuffer([]byte{})
|
||||
err = p.PrintObj(testObject, out)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
match, err := regexp.Match(tc.expectedOutput, out.Bytes())
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if !match {
|
||||
t.Errorf("unexpected output: expecting %q, got %q", tc.expectedOutput, out.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
155
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/label.go
generated
vendored
155
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/label.go
generated
vendored
@ -18,7 +18,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
@ -28,16 +27,19 @@ import (
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
|
||||
@ -45,6 +47,10 @@ import (
|
||||
type LabelOptions struct {
|
||||
// Filename options
|
||||
resource.FilenameOptions
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
ToPrinter func(string) (printers.ResourcePrinter, error)
|
||||
|
||||
// Common user flags
|
||||
overwrite bool
|
||||
@ -54,6 +60,7 @@ type LabelOptions struct {
|
||||
all bool
|
||||
resourceVersion string
|
||||
selector string
|
||||
fieldSelector string
|
||||
outputFormat string
|
||||
|
||||
// results of arg parsing
|
||||
@ -61,8 +68,16 @@ type LabelOptions struct {
|
||||
newLabels map[string]string
|
||||
removeLabels []string
|
||||
|
||||
Recorder genericclioptions.Recorder
|
||||
|
||||
namespace string
|
||||
enforceNamespace bool
|
||||
includeUninitialized bool
|
||||
builder *resource.Builder
|
||||
unstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
|
||||
// Common shared fields
|
||||
out io.Writer
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
@ -95,9 +110,19 @@ var (
|
||||
kubectl label pods foo bar-`))
|
||||
)
|
||||
|
||||
func NewCmdLabel(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := &LabelOptions{}
|
||||
validArgs := cmdutil.ValidArgList(f)
|
||||
func NewLabelOptions(ioStreams genericclioptions.IOStreams) *LabelOptions {
|
||||
return &LabelOptions{
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
|
||||
PrintFlags: genericclioptions.NewPrintFlags("labeled").WithTypeSetter(scheme.Scheme),
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdLabel(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewLabelOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "label [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version]",
|
||||
@ -106,40 +131,52 @@ func NewCmdLabel(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
Long: fmt.Sprintf(labelLong, validation.LabelValueMaxLength),
|
||||
Example: labelExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if err := options.Complete(out, cmd, args); err != nil {
|
||||
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, err.Error()))
|
||||
}
|
||||
if err := options.Validate(); err != nil {
|
||||
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, err.Error()))
|
||||
}
|
||||
cmdutil.CheckErr(options.RunLabel(f, cmd))
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.RunLabel())
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
}
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmd.Flags().BoolVar(&options.overwrite, "overwrite", options.overwrite, "If true, allow labels to be overwritten, otherwise reject label updates that overwrite existing labels.")
|
||||
cmd.Flags().BoolVar(&options.list, "list", options.list, "If true, display the labels for a given resource.")
|
||||
cmd.Flags().BoolVar(&options.local, "local", options.local, "If true, label will NOT contact api-server but run locally.")
|
||||
cmd.Flags().StringVarP(&options.selector, "selector", "l", options.selector, "Selector (label query) to filter on, not including uninitialized ones, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2).")
|
||||
cmd.Flags().BoolVar(&options.all, "all", options.all, "Select all resources, including uninitialized ones, in the namespace of the specified resource types")
|
||||
cmd.Flags().StringVar(&options.resourceVersion, "resource-version", options.resourceVersion, i18n.T("If non-empty, the labels update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource."))
|
||||
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmd.Flags().BoolVar(&o.overwrite, "overwrite", o.overwrite, "If true, allow labels to be overwritten, otherwise reject label updates that overwrite existing labels.")
|
||||
cmd.Flags().BoolVar(&o.list, "list", o.list, "If true, display the labels for a given resource.")
|
||||
cmd.Flags().BoolVar(&o.local, "local", o.local, "If true, label will NOT contact api-server but run locally.")
|
||||
cmd.Flags().StringVarP(&o.selector, "selector", "l", o.selector, "Selector (label query) to filter on, not including uninitialized ones, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2).")
|
||||
cmd.Flags().StringVar(&o.fieldSelector, "field-selector", o.fieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.")
|
||||
cmd.Flags().BoolVar(&o.all, "all", o.all, "Select all resources, including uninitialized ones, in the namespace of the specified resource types")
|
||||
cmd.Flags().StringVar(&o.resourceVersion, "resource-version", o.resourceVersion, i18n.T("If non-empty, the labels update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource."))
|
||||
usage := "identifying the resource to update the labels"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Complete adapts from the command line args and factory to the data required.
|
||||
func (o *LabelOptions) Complete(out io.Writer, cmd *cobra.Command, args []string) (err error) {
|
||||
o.out = out
|
||||
func (o *LabelOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
var err error
|
||||
|
||||
o.RecordFlags.Complete(cmd)
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.outputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
o.dryrun = cmdutil.GetDryRunFlag(cmd)
|
||||
|
||||
o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) {
|
||||
o.PrintFlags.NamePrintFlags.Operation = operation
|
||||
if o.dryrun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
|
||||
return o.PrintFlags.ToPrinter()
|
||||
}
|
||||
|
||||
resources, labelArgs, err := cmdutil.GetResourcesAndPairs(args, "label")
|
||||
if err != nil {
|
||||
return err
|
||||
@ -148,10 +185,18 @@ func (o *LabelOptions) Complete(out io.Writer, cmd *cobra.Command, args []string
|
||||
o.newLabels, o.removeLabels, err = parseLabels(labelArgs)
|
||||
|
||||
if o.list && len(o.outputFormat) > 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "--list and --output may not be specified together")
|
||||
return fmt.Errorf("--list and --output may not be specified together")
|
||||
}
|
||||
|
||||
return err
|
||||
o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.includeUninitialized = cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
o.builder = f.NewBuilder()
|
||||
o.unstructuredClientForMapping = f.UnstructuredClientForMapping
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate checks to the LabelOptions to see if there is sufficient information run the command.
|
||||
@ -159,6 +204,9 @@ func (o *LabelOptions) Validate() error {
|
||||
if o.all && len(o.selector) > 0 {
|
||||
return fmt.Errorf("cannot set --all and --selector at the same time")
|
||||
}
|
||||
if o.all && len(o.fieldSelector) > 0 {
|
||||
return fmt.Errorf("cannot set --all and --field-selector at the same time")
|
||||
}
|
||||
if len(o.resources) < 1 && cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames) {
|
||||
return fmt.Errorf("one or more resources must be specified as <resource> <name> or <resource>/<name>")
|
||||
}
|
||||
@ -169,26 +217,19 @@ func (o *LabelOptions) Validate() error {
|
||||
}
|
||||
|
||||
// RunLabel does the work
|
||||
func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
changeCause := f.Command(cmd, false)
|
||||
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
b := f.NewBuilder().
|
||||
func (o *LabelOptions) RunLabel() error {
|
||||
b := o.builder.
|
||||
Unstructured().
|
||||
LocalParam(o.local).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
IncludeUninitialized(includeUninitialized).
|
||||
NamespaceParam(o.namespace).DefaultNamespace().
|
||||
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
|
||||
IncludeUninitialized(o.includeUninitialized).
|
||||
Flatten()
|
||||
|
||||
if !o.local {
|
||||
b = b.LabelSelectorParam(o.selector).
|
||||
FieldSelectorParam(o.fieldSelector).
|
||||
ResourceTypeOrNameArgs(o.all, o.resources...).
|
||||
Latest()
|
||||
}
|
||||
@ -232,17 +273,15 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
}
|
||||
for _, label := range o.removeLabels {
|
||||
if _, ok := accessor.GetLabels()[label]; !ok {
|
||||
fmt.Fprintf(o.out, "label %q not found.\n", label)
|
||||
fmt.Fprintf(o.Out, "label %q not found.\n", label)
|
||||
}
|
||||
}
|
||||
|
||||
if err := labelFunc(obj, o.overwrite, o.resourceVersion, o.newLabels, o.removeLabels); err != nil {
|
||||
return err
|
||||
}
|
||||
if cmdutil.ShouldRecord(cmd, info) {
|
||||
if err := cmdutil.RecordChangeCause(obj, changeCause); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := o.Recorder.Record(obj); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
newData, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
@ -258,7 +297,7 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
}
|
||||
|
||||
mapping := info.ResourceMapping()
|
||||
client, err := f.UnstructuredClientForMapping(mapping)
|
||||
client, err := o.unstructuredClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -280,17 +319,27 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
return err
|
||||
}
|
||||
|
||||
indent := ""
|
||||
if !one {
|
||||
indent = " "
|
||||
gvks, _, err := unstructuredscheme.NewUnstructuredObjectTyper().ObjectKinds(info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(o.ErrOut, "Listing labels for %s.%s/%s:\n", gvks[0].Kind, gvks[0].Group, info.Name)
|
||||
}
|
||||
for k, v := range accessor.GetLabels() {
|
||||
fmt.Fprintf(o.out, "%s=%s\n", k, v)
|
||||
fmt.Fprintf(o.Out, "%s%s=%s\n", indent, k, v)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(o.outputFormat) > 0 {
|
||||
return cmdutil.PrintObject(cmd, outputObj, o.out)
|
||||
printer, err := o.ToPrinter(dataChangeMsg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmdutil.PrintSuccess(false, o.out, info.Object, o.dryrun, dataChangeMsg)
|
||||
printer.PrintObj(info.Object, o.Out)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
110
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/label_test.go
generated
vendored
110
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/label_test.go
generated
vendored
@ -29,7 +29,7 @@ import (
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
@ -321,39 +321,45 @@ func TestLabelErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
for k, testCase := range testCases {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
t.Run(k, func(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdLabel(tf, buf)
|
||||
cmd.SetOutput(buf)
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
for k, v := range testCase.flags {
|
||||
cmd.Flags().Set(k, v)
|
||||
}
|
||||
opts := LabelOptions{}
|
||||
err := opts.Complete(buf, cmd, testCase.args)
|
||||
if err == nil {
|
||||
err = opts.Validate()
|
||||
}
|
||||
if err == nil {
|
||||
err = opts.RunLabel(tf, cmd)
|
||||
}
|
||||
if !testCase.errFn(err) {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
continue
|
||||
}
|
||||
if buf.Len() > 0 {
|
||||
t.Errorf("buffer should be empty: %s", string(buf.Bytes()))
|
||||
}
|
||||
ioStreams, _, _, _ := genericclioptions.NewTestIOStreams()
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdLabel(tf, ioStreams)
|
||||
cmd.SetOutput(buf)
|
||||
|
||||
for k, v := range testCase.flags {
|
||||
cmd.Flags().Set(k, v)
|
||||
}
|
||||
opts := NewLabelOptions(ioStreams)
|
||||
err := opts.Complete(tf, cmd, testCase.args)
|
||||
if err == nil {
|
||||
err = opts.Validate()
|
||||
}
|
||||
if err == nil {
|
||||
err = opts.RunLabel()
|
||||
}
|
||||
if !testCase.errFn(err) {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
return
|
||||
}
|
||||
if buf.Len() > 0 {
|
||||
t.Errorf("buffer should be empty: %s", string(buf.Bytes()))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelForResourceFromFile(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -381,19 +387,18 @@ func TestLabelForResourceFromFile(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdLabel(tf, buf)
|
||||
opts := LabelOptions{FilenameOptions: resource.FilenameOptions{
|
||||
Filenames: []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}}}
|
||||
err := opts.Complete(buf, cmd, []string{"a=b"})
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdLabel(tf, ioStreams)
|
||||
opts := NewLabelOptions(ioStreams)
|
||||
opts.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
|
||||
err := opts.Complete(tf, cmd, []string{"a=b"})
|
||||
if err == nil {
|
||||
err = opts.Validate()
|
||||
}
|
||||
if err == nil {
|
||||
err = opts.RunLabel(tf, cmd)
|
||||
err = opts.RunLabel()
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
@ -404,7 +409,9 @@ func TestLabelForResourceFromFile(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLabelLocal(t *testing.T) {
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
@ -412,20 +419,19 @@ func TestLabelLocal(t *testing.T) {
|
||||
return nil, nil
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdLabel(tf, buf)
|
||||
opts := LabelOptions{FilenameOptions: resource.FilenameOptions{
|
||||
Filenames: []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}},
|
||||
local: true}
|
||||
err := opts.Complete(buf, cmd, []string{"a=b"})
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
cmd := NewCmdLabel(tf, ioStreams)
|
||||
opts := NewLabelOptions(ioStreams)
|
||||
opts.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
|
||||
opts.local = true
|
||||
err := opts.Complete(tf, cmd, []string{"a=b"})
|
||||
if err == nil {
|
||||
err = opts.Validate()
|
||||
}
|
||||
if err == nil {
|
||||
err = opts.RunLabel(tf, cmd)
|
||||
err = opts.RunLabel()
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
@ -437,8 +443,10 @@ func TestLabelLocal(t *testing.T) {
|
||||
|
||||
func TestLabelMultipleObjects(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@ -468,18 +476,18 @@ func TestLabelMultipleObjects(t *testing.T) {
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdLabel(tf, buf)
|
||||
opts := LabelOptions{all: true}
|
||||
err := opts.Complete(buf, cmd, []string{"pods", "a=b"})
|
||||
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
opts := NewLabelOptions(ioStreams)
|
||||
opts.all = true
|
||||
cmd := NewCmdLabel(tf, ioStreams)
|
||||
err := opts.Complete(tf, cmd, []string{"pods", "a=b"})
|
||||
if err == nil {
|
||||
err = opts.Validate()
|
||||
}
|
||||
if err == nil {
|
||||
err = opts.RunLabel(tf, cmd)
|
||||
err = opts.RunLabel()
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
|
94
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/logs.go
generated
vendored
94
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/logs.go
generated
vendored
@ -18,20 +18,22 @@ package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
@ -41,8 +43,11 @@ var (
|
||||
# Return snapshot logs from pod nginx with only one container
|
||||
kubectl logs nginx
|
||||
|
||||
# Return snapshot logs for the pods defined by label app=nginx
|
||||
kubectl logs -lapp=nginx
|
||||
# Return snapshot logs from pod nginx with multi containers
|
||||
kubectl logs nginx --all-containers=true
|
||||
|
||||
# Return snapshot logs from all containers in pods defined by label app=nginx
|
||||
kubectl logs -lapp=nginx --all-containers=true
|
||||
|
||||
# Return snapshot of previous terminated ruby container logs from pod web-1
|
||||
kubectl logs -p -c ruby web-1
|
||||
@ -70,24 +75,30 @@ const (
|
||||
)
|
||||
|
||||
type LogsOptions struct {
|
||||
Namespace string
|
||||
ResourceArg string
|
||||
Options runtime.Object
|
||||
Namespace string
|
||||
ResourceArg string
|
||||
AllContainers bool
|
||||
Options runtime.Object
|
||||
|
||||
Mapper meta.RESTMapper
|
||||
Typer runtime.ObjectTyper
|
||||
Decoder runtime.Decoder
|
||||
Object runtime.Object
|
||||
GetPodTimeout time.Duration
|
||||
RESTClientGetter genericclioptions.RESTClientGetter
|
||||
LogsForObject polymorphichelpers.LogsForObjectFunc
|
||||
|
||||
Object runtime.Object
|
||||
GetPodTimeout time.Duration
|
||||
LogsForObject func(object, options runtime.Object, timeout time.Duration) (*restclient.Request, error)
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
Out io.Writer
|
||||
func NewLogsOptions(streams genericclioptions.IOStreams, allContainers bool) *LogsOptions {
|
||||
return &LogsOptions{
|
||||
IOStreams: streams,
|
||||
AllContainers: allContainers,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCmdLogs creates a new pod logs command
|
||||
func NewCmdLogs(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
o := &LogsOptions{}
|
||||
func NewCmdLogs(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewLogsOptions(streams, false)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "logs [-f] [-p] (POD | TYPE/NAME) [-c CONTAINER]",
|
||||
DisableFlagsInUseLine: true,
|
||||
@ -96,16 +107,17 @@ func NewCmdLogs(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
Example: logsExample,
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
if len(os.Args) > 1 && os.Args[1] == "log" {
|
||||
printDeprecationWarning(errOut, "logs", "log")
|
||||
printDeprecationWarning(o.ErrOut, "logs", "log")
|
||||
}
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(f, out, cmd, args))
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.RunLogs())
|
||||
},
|
||||
Aliases: []string{"log"},
|
||||
}
|
||||
cmd.Flags().BoolVar(&o.AllContainers, "all-containers", o.AllContainers, "Get all containers's logs in the pod(s).")
|
||||
cmd.Flags().BoolP("follow", "f", false, "Specify if the logs should be streamed.")
|
||||
cmd.Flags().Bool("timestamps", false, "Include timestamps on each line in the log output")
|
||||
cmd.Flags().Int64("limit-bytes", 0, "Maximum bytes of logs to return. Defaults to no limit.")
|
||||
@ -116,13 +128,12 @@ func NewCmdLogs(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
cmd.Flags().StringP("container", "c", "", "Print the logs of this container")
|
||||
cmd.Flags().Bool("interactive", false, "If true, prompt the user for input when required.")
|
||||
cmd.Flags().MarkDeprecated("interactive", "This flag is no longer respected and there is no replacement.")
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
cmdutil.AddPodRunningTimeoutFlag(cmd, defaultPodLogsTimeout)
|
||||
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on.")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *LogsOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
||||
func (o *LogsOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
containerName := cmdutil.GetFlagString(cmd, "container")
|
||||
selector := cmdutil.GetFlagString(cmd, "selector")
|
||||
switch len(args) {
|
||||
@ -145,7 +156,7 @@ func (o *LogsOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Comm
|
||||
return cmdutil.UsageErrorf(cmd, "%s", logsUsageStr)
|
||||
}
|
||||
var err error
|
||||
o.Namespace, _, err = f.DefaultNamespace()
|
||||
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -172,7 +183,7 @@ func (o *LogsOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Comm
|
||||
}
|
||||
if sinceSeconds := cmdutil.GetFlagDuration(cmd, "since"); sinceSeconds != 0 {
|
||||
// round up to the nearest second
|
||||
sec := int64(math.Ceil(float64(sinceSeconds) / float64(time.Second)))
|
||||
sec := int64(sinceSeconds.Round(time.Second).Seconds())
|
||||
logOptions.SinceSeconds = &sec
|
||||
}
|
||||
o.GetPodTimeout, err = cmdutil.GetPodRunningTimeoutFlag(cmd)
|
||||
@ -180,8 +191,8 @@ func (o *LogsOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Comm
|
||||
return err
|
||||
}
|
||||
o.Options = logOptions
|
||||
o.LogsForObject = f.LogsForObject
|
||||
o.Out = out
|
||||
o.RESTClientGetter = f
|
||||
o.LogsForObject = polymorphichelpers.LogsForObjectFn
|
||||
|
||||
if len(selector) != 0 {
|
||||
if logOptions.Follow {
|
||||
@ -194,7 +205,7 @@ func (o *LogsOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Comm
|
||||
|
||||
if o.Object == nil {
|
||||
builder := f.NewBuilder().
|
||||
Internal().
|
||||
WithScheme(legacyscheme.Scheme).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
SingleResourceType()
|
||||
if o.ResourceArg != "" {
|
||||
@ -221,6 +232,9 @@ func (o LogsOptions) Validate() error {
|
||||
if !ok {
|
||||
return errors.New("unexpected logs options object")
|
||||
}
|
||||
if o.AllContainers && len(logsOptions.Container) > 0 {
|
||||
return fmt.Errorf("--all-containers=true should not be specified with container name %s", logsOptions.Container)
|
||||
}
|
||||
if errs := validation.ValidatePodLogOptions(logsOptions); len(errs) > 0 {
|
||||
return errs.ToAggregate()
|
||||
}
|
||||
@ -233,18 +247,42 @@ func (o LogsOptions) RunLogs() error {
|
||||
switch t := o.Object.(type) {
|
||||
case *api.PodList:
|
||||
for _, p := range t.Items {
|
||||
if err := o.getLogs(&p); err != nil {
|
||||
if err := o.getPodLogs(&p); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case *api.Pod:
|
||||
return o.getPodLogs(t)
|
||||
default:
|
||||
return o.getLogs(o.Object)
|
||||
}
|
||||
}
|
||||
|
||||
// getPodLogs checks whether o.AllContainers is set to true.
|
||||
// If so, it retrives all containers' log in the pod.
|
||||
func (o LogsOptions) getPodLogs(pod *api.Pod) error {
|
||||
if !o.AllContainers {
|
||||
return o.getLogs(pod)
|
||||
}
|
||||
|
||||
for _, c := range pod.Spec.InitContainers {
|
||||
o.Options.(*api.PodLogOptions).Container = c.Name
|
||||
if err := o.getLogs(pod); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, c := range pod.Spec.Containers {
|
||||
o.Options.(*api.PodLogOptions).Container = c.Name
|
||||
if err := o.getLogs(pod); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o LogsOptions) getLogs(obj runtime.Object) error {
|
||||
req, err := o.LogsForObject(obj, o.Options, o.GetPodTimeout)
|
||||
req, err := o.LogsForObject(o.RESTClientGetter, obj, o.Options, o.GetPodTimeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
130
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/logs_test.go
generated
vendored
130
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/logs_test.go
generated
vendored
@ -18,19 +18,27 @@ package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"fmt"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
@ -48,39 +56,51 @@ func TestLog(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
logContent := "test log content"
|
||||
tf := cmdtesting.NewTestFactory()
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
|
||||
ns := legacyscheme.Codecs
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
logContent := "test log content"
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == test.podPath && m == "GET":
|
||||
body := objBody(codec, test.pod)
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
case p == test.logPath && m == "GET":
|
||||
body := ioutil.NopCloser(bytes.NewBufferString(logContent))
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
default:
|
||||
// Ensures no GET is performed when deleting by name
|
||||
t.Errorf("%s: unexpected request: %#v\n%#v", test.name, req.URL, req)
|
||||
return nil, nil
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||
ns := legacyscheme.Codecs
|
||||
|
||||
cmd := NewCmdLogs(tf, buf, buf)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Run(cmd, []string{"foo"})
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == test.podPath && m == "GET":
|
||||
body := objBody(codec, test.pod)
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
case p == test.logPath && m == "GET":
|
||||
body := ioutil.NopCloser(bytes.NewBufferString(logContent))
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
default:
|
||||
t.Errorf("%s: unexpected request: %#v\n%#v", test.name, req.URL, req)
|
||||
return nil, nil
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.ClientConfigVal = defaultClientConfig()
|
||||
oldLogFn := polymorphichelpers.LogsForObjectFn
|
||||
defer func() {
|
||||
polymorphichelpers.LogsForObjectFn = oldLogFn
|
||||
}()
|
||||
clientset, err := tf.ClientSet()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
polymorphichelpers.LogsForObjectFn = logTestMock{client: clientset}.logsForObject
|
||||
|
||||
if buf.String() != logContent {
|
||||
t.Errorf("%s: did not get expected log content. Got: %s", test.name, buf.String())
|
||||
}
|
||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||
|
||||
cmd := NewCmdLogs(tf, streams)
|
||||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Run(cmd, []string{"foo"})
|
||||
|
||||
if buf.String() != logContent {
|
||||
t.Errorf("%s: did not get expected log content. Got: %s", test.name, buf.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,48 +121,61 @@ func testPod() *api.Pod {
|
||||
|
||||
func TestValidateLogFlags(t *testing.T) {
|
||||
f := cmdtesting.NewTestFactory()
|
||||
defer f.Cleanup()
|
||||
f.WithNamespace("")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
flags map[string]string
|
||||
args []string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "since & since-time",
|
||||
flags: map[string]string{"since": "1h", "since-time": "2006-01-02T15:04:05Z"},
|
||||
args: []string{"foo"},
|
||||
expected: "at most one of `sinceTime` or `sinceSeconds` may be specified",
|
||||
},
|
||||
{
|
||||
name: "negative since-time",
|
||||
flags: map[string]string{"since": "-1s"},
|
||||
args: []string{"foo"},
|
||||
expected: "must be greater than 0",
|
||||
},
|
||||
{
|
||||
name: "negative limit-bytes",
|
||||
flags: map[string]string{"limit-bytes": "-100"},
|
||||
args: []string{"foo"},
|
||||
expected: "must be greater than 0",
|
||||
},
|
||||
{
|
||||
name: "negative tail",
|
||||
flags: map[string]string{"tail": "-100"},
|
||||
args: []string{"foo"},
|
||||
expected: "must be greater than or equal to 0",
|
||||
},
|
||||
{
|
||||
name: "container name combined with --all-containers",
|
||||
flags: map[string]string{"all-containers": "true"},
|
||||
args: []string{"my-pod", "my-container"},
|
||||
expected: "--all-containers=true should not be specified with container",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdLogs(f, buf, buf)
|
||||
streams := genericclioptions.NewTestIOStreamsDiscard()
|
||||
cmd := NewCmdLogs(f, streams)
|
||||
out := ""
|
||||
for flag, value := range test.flags {
|
||||
cmd.Flags().Set(flag, value)
|
||||
}
|
||||
// checkErr breaks tests in case of errors, plus we just
|
||||
// need to check errors returned by the command validation
|
||||
o := &LogsOptions{}
|
||||
o := NewLogsOptions(streams, test.flags["all-containers"] == "true")
|
||||
cmd.Run = func(cmd *cobra.Command, args []string) {
|
||||
o.Complete(f, os.Stdout, cmd, args)
|
||||
o.Complete(f, cmd, args)
|
||||
out = o.Validate().Error()
|
||||
}
|
||||
cmd.Run(cmd, []string{"foo"})
|
||||
cmd.Run(cmd, test.args)
|
||||
|
||||
if !strings.Contains(out, test.expected) {
|
||||
t.Errorf("%s: expected to find:\n\t%s\nfound:\n\t%s\n", test.name, test.expected, out)
|
||||
@ -152,6 +185,7 @@ func TestValidateLogFlags(t *testing.T) {
|
||||
|
||||
func TestLogComplete(t *testing.T) {
|
||||
f := cmdtesting.NewTestFactory()
|
||||
defer f.Cleanup()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@ -189,8 +223,7 @@ func TestLogComplete(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdLogs(f, buf, buf)
|
||||
cmd := NewCmdLogs(f, genericclioptions.NewTestIOStreamsDiscard())
|
||||
var err error
|
||||
out := ""
|
||||
for flag, value := range test.flags {
|
||||
@ -198,11 +231,28 @@ func TestLogComplete(t *testing.T) {
|
||||
}
|
||||
// checkErr breaks tests in case of errors, plus we just
|
||||
// need to check errors returned by the command validation
|
||||
o := &LogsOptions{}
|
||||
err = o.Complete(f, os.Stdout, cmd, test.args)
|
||||
o := NewLogsOptions(genericclioptions.NewTestIOStreamsDiscard(), false)
|
||||
err = o.Complete(f, cmd, test.args)
|
||||
out = err.Error()
|
||||
if !strings.Contains(out, test.expected) {
|
||||
t.Errorf("%s: expected to find:\n\t%s\nfound:\n\t%s\n", test.name, test.expected, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type logTestMock struct {
|
||||
client internalclientset.Interface
|
||||
}
|
||||
|
||||
func (m logTestMock) logsForObject(restClientGetter genericclioptions.RESTClientGetter, object, options runtime.Object, timeout time.Duration) (*restclient.Request, error) {
|
||||
switch t := object.(type) {
|
||||
case *api.Pod:
|
||||
opts, ok := options.(*api.PodLogOptions)
|
||||
if !ok {
|
||||
return nil, errors.New("provided options object is not a PodLogOptions")
|
||||
}
|
||||
return m.client.Core().Pods(t.Namespace).GetLogs(t.Name, opts), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("cannot get the logs from %T", object)
|
||||
}
|
||||
}
|
||||
|
215
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/patch.go
generated
vendored
215
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/patch.go
generated
vendored
@ -18,7 +18,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
@ -26,18 +25,19 @@ import (
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
)
|
||||
@ -49,9 +49,24 @@ var patchTypes = map[string]types.PatchType{"json": types.JSONPatchType, "merge"
|
||||
type PatchOptions struct {
|
||||
resource.FilenameOptions
|
||||
|
||||
Local bool
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
ToPrinter func(string) (printers.ResourcePrinter, error)
|
||||
Recorder genericclioptions.Recorder
|
||||
|
||||
OutputFormat string
|
||||
Local bool
|
||||
PatchType string
|
||||
Patch string
|
||||
|
||||
namespace string
|
||||
enforceNamespace bool
|
||||
dryRun bool
|
||||
outputFormat string
|
||||
args []string
|
||||
builder *resource.Builder
|
||||
unstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
@ -79,9 +94,17 @@ var (
|
||||
kubectl patch pod valid-pod --type='json' -p='[{"op": "replace", "path": "/spec/containers/0/image", "value":"new image"}]'`))
|
||||
)
|
||||
|
||||
func NewCmdPatch(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := &PatchOptions{}
|
||||
validArgs := cmdutil.ValidArgList(f)
|
||||
func NewPatchOptions(ioStreams genericclioptions.IOStreams) *PatchOptions {
|
||||
return &PatchOptions{
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
PrintFlags: genericclioptions.NewPrintFlags("patched").WithTypeSetter(scheme.Scheme),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdPatch(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewPatchOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "patch (-f FILENAME | TYPE NAME) -p PATCH",
|
||||
@ -90,65 +113,89 @@ func NewCmdPatch(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
Long: patchLong,
|
||||
Example: patchExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
options.OutputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
err := RunPatch(f, out, cmd, args, options)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.RunPatch())
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
}
|
||||
cmd.Flags().StringP("patch", "p", "", "The patch to be applied to the resource JSON file.")
|
||||
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmd.Flags().StringVarP(&o.Patch, "patch", "p", "", "The patch to be applied to the resource JSON file.")
|
||||
cmd.MarkFlagRequired("patch")
|
||||
cmd.Flags().String("type", "strategic", fmt.Sprintf("The type of patch being provided; one of %v", sets.StringKeySet(patchTypes).List()))
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
|
||||
usage := "identifying the resource to update"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
|
||||
cmd.Flags().BoolVar(&options.Local, "local", options.Local, "If true, patch will operate on the content of the file, not the server-side resource.")
|
||||
cmd.Flags().StringVar(&o.PatchType, "type", "strategic", fmt.Sprintf("The type of patch being provided; one of %v", sets.StringKeySet(patchTypes).List()))
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "identifying the resource to update")
|
||||
cmd.Flags().BoolVar(&o.Local, "local", o.Local, "If true, patch will operate on the content of the file, not the server-side resource.")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *PatchOptions) error {
|
||||
switch {
|
||||
case options.Local && len(args) != 0:
|
||||
return fmt.Errorf("cannot specify --local and server resources")
|
||||
}
|
||||
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
func (o *PatchOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
var err error
|
||||
o.RecordFlags.Complete(cmd)
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
patchType := types.StrategicMergePatchType
|
||||
patchTypeString := strings.ToLower(cmdutil.GetFlagString(cmd, "type"))
|
||||
if len(patchTypeString) != 0 {
|
||||
ok := false
|
||||
patchType, ok = patchTypes[patchTypeString]
|
||||
if !ok {
|
||||
return cmdutil.UsageErrorf(cmd, "--type must be one of %v, not %q",
|
||||
sets.StringKeySet(patchTypes).List(), patchTypeString)
|
||||
o.outputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
o.dryRun = cmdutil.GetFlagBool(cmd, "dry-run")
|
||||
|
||||
o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) {
|
||||
o.PrintFlags.NamePrintFlags.Operation = operation
|
||||
if o.dryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
|
||||
return o.PrintFlags.ToPrinter()
|
||||
}
|
||||
|
||||
o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.args = args
|
||||
o.builder = f.NewBuilder()
|
||||
o.unstructuredClientForMapping = f.UnstructuredClientForMapping
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *PatchOptions) Validate() error {
|
||||
if o.Local && len(o.args) != 0 {
|
||||
return fmt.Errorf("cannot specify --local and server resources")
|
||||
}
|
||||
if len(o.Patch) == 0 {
|
||||
return fmt.Errorf("must specify -p to patch")
|
||||
}
|
||||
if len(o.PatchType) != 0 {
|
||||
if _, ok := patchTypes[strings.ToLower(o.PatchType)]; !ok {
|
||||
return fmt.Errorf("--type must be one of %v, not %q", sets.StringKeySet(patchTypes).List(), o.PatchType)
|
||||
}
|
||||
}
|
||||
|
||||
patch := cmdutil.GetFlagString(cmd, "patch")
|
||||
if len(patch) == 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "Must specify -p to patch")
|
||||
}
|
||||
patchBytes, err := yaml.ToJSON([]byte(patch))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to parse %q: %v", patch, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *PatchOptions) RunPatch() error {
|
||||
patchType := types.StrategicMergePatchType
|
||||
if len(o.PatchType) != 0 {
|
||||
patchType = patchTypes[strings.ToLower(o.PatchType)]
|
||||
}
|
||||
|
||||
r := f.NewBuilder().
|
||||
patchBytes, err := yaml.ToJSON([]byte(o.Patch))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to parse %q: %v", o.Patch, err)
|
||||
}
|
||||
|
||||
r := o.builder.
|
||||
Unstructured().
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &options.FilenameOptions).
|
||||
ResourceTypeOrNameArgs(false, args...).
|
||||
NamespaceParam(o.namespace).DefaultNamespace().
|
||||
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
|
||||
ResourceTypeOrNameArgs(false, o.args...).
|
||||
Flatten().
|
||||
Do()
|
||||
err = r.Err()
|
||||
@ -163,56 +210,42 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
|
||||
}
|
||||
name, namespace := info.Name, info.Namespace
|
||||
mapping := info.ResourceMapping()
|
||||
client, err := f.UnstructuredClientForMapping(mapping)
|
||||
client, err := o.unstructuredClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !options.Local {
|
||||
dataChangedMsg := "not patched"
|
||||
didPatch := false
|
||||
if !o.Local && !o.dryRun {
|
||||
helper := resource.NewHelper(client, mapping)
|
||||
patchedObj, err := helper.Patch(namespace, name, patchType, patchBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Record the change as a second patch to avoid trying to merge with a user's patch data
|
||||
if cmdutil.ShouldRecord(cmd, info) {
|
||||
// Copy the resource info and update with the result of applying the user's patch
|
||||
infoCopy := *info
|
||||
infoCopy.Object = patchedObj
|
||||
if patch, patchType, err := cmdutil.ChangeResourcePatch(&infoCopy, f.Command(cmd, true)); err == nil {
|
||||
if recordedObj, err := helper.Patch(info.Namespace, info.Name, patchType, patch); err != nil {
|
||||
glog.V(4).Infof("error recording reason: %v", err)
|
||||
} else {
|
||||
patchedObj = recordedObj
|
||||
}
|
||||
|
||||
didPatch := !reflect.DeepEqual(info.Object, patchedObj)
|
||||
|
||||
// if the recorder makes a change, compute and create another patch
|
||||
if mergePatch, err := o.Recorder.MakeRecordMergePatch(patchedObj); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
} else if len(mergePatch) > 0 {
|
||||
if recordedObj, err := helper.Patch(info.Namespace, info.Name, types.MergePatchType, mergePatch); err != nil {
|
||||
glog.V(4).Infof("error recording reason: %v", err)
|
||||
} else {
|
||||
patchedObj = recordedObj
|
||||
}
|
||||
}
|
||||
count++
|
||||
|
||||
oldData, err := json.Marshal(info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newData, err := json.Marshal(patchedObj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !reflect.DeepEqual(oldData, newData) {
|
||||
didPatch = true
|
||||
dataChangedMsg = "patched"
|
||||
}
|
||||
|
||||
// After computing whether we changed data, refresh the resource info with the resulting object
|
||||
if err := info.Refresh(patchedObj, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(options.OutputFormat) > 0 && options.OutputFormat != "name" {
|
||||
return cmdutil.PrintObject(cmd, info.Object, out)
|
||||
printer, err := o.ToPrinter(patchOperation(didPatch))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmdutil.PrintSuccess(options.OutputFormat == "name", out, info.Object, false, dataChangedMsg)
|
||||
printer.PrintObj(info.Object, o.Out)
|
||||
|
||||
// if object was not successfully patched, exit with error code 1
|
||||
if !didPatch {
|
||||
@ -239,14 +272,23 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
|
||||
return err
|
||||
}
|
||||
|
||||
didPatch := !reflect.DeepEqual(info.Object, targetObj)
|
||||
|
||||
// TODO: if we ever want to go generic, this allows a clean -o yaml without trying to print columns or anything
|
||||
// rawExtension := &runtime.Unknown{
|
||||
// Raw: originalPatchedObjJS,
|
||||
// }
|
||||
if err := info.Refresh(targetObj, true); err != nil {
|
||||
if didPatch {
|
||||
if err := info.Refresh(targetObj, true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
printer, err := o.ToPrinter(patchOperation(didPatch))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cmdutil.PrintObject(cmd, info.Object, out)
|
||||
return printer.PrintObj(info.Object, o.Out)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@ -282,3 +324,10 @@ func getPatchedJSON(patchType types.PatchType, originalJS, patchJS []byte, gvk s
|
||||
return nil, fmt.Errorf("unknown Content-Type header for patch: %v", patchType)
|
||||
}
|
||||
}
|
||||
|
||||
func patchOperation(didPatch bool) string {
|
||||
if didPatch {
|
||||
return "patched"
|
||||
}
|
||||
return "not patched"
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user