mirror of https://github.com/k3s-io/k3s
wire printflags through additional cmds
parent
29630b5124
commit
27bd4ded04
|
@ -2843,7 +2843,7 @@ run_rc_tests() {
|
|||
# Pre-condition: default run without --name flag; should succeed by truncating the inherited name
|
||||
output_message=$(kubectl expose -f hack/testdata/pod-with-large-name.yaml --port=8081 2>&1 "${kube_flags[@]}")
|
||||
# Post-condition: inherited name from pod has been truncated
|
||||
kube::test::if_has_string "${output_message}" '\"kubernetes-serve-hostname-testing-sixty-three-characters-in-len\" exposed'
|
||||
kube::test::if_has_string "${output_message}" 'kubernetes-serve-hostname-testing-sixty-three-characters-in-len exposed'
|
||||
# Clean-up
|
||||
kubectl delete svc kubernetes-serve-hostname-testing-sixty-three-characters-in-len "${kube_flags[@]}"
|
||||
|
||||
|
@ -2851,7 +2851,7 @@ run_rc_tests() {
|
|||
# Pre-condition: don't use --port flag
|
||||
output_message=$(kubectl expose -f test/fixtures/doc-yaml/admin/high-availability/etcd.yaml --selector=test=etcd 2>&1 "${kube_flags[@]}")
|
||||
# Post-condition: expose succeeded
|
||||
kube::test::if_has_string "${output_message}" '\"etcd-server\" exposed'
|
||||
kube::test::if_has_string "${output_message}" 'etcd-server\" exposed'
|
||||
# Post-condition: generated service has both ports from the exposed pod
|
||||
kube::test::get_object_assert 'service etcd-server' "{{$port_name}} {{$port_field}}" 'port-1 2380'
|
||||
kube::test::get_object_assert 'service etcd-server' "{{$second_port_name}} {{$second_port_field}}" 'port-2 2379'
|
||||
|
@ -4647,7 +4647,7 @@ __EOF__
|
|||
kube::test::if_has_string "${response}" 'must provide one or more resources'
|
||||
# test=label matches our node
|
||||
response=$(kubectl cordon --selector test=label)
|
||||
kube::test::if_has_string "${response}" 'node "127.0.0.1" cordoned'
|
||||
kube::test::if_has_string "${response}" 'node/127.0.0.1 cordoned'
|
||||
# invalid=label does not match any nodes
|
||||
response=$(kubectl cordon --selector invalid=label)
|
||||
kube::test::if_has_not_string "${response}" 'cordoned'
|
||||
|
|
|
@ -19,6 +19,7 @@ package cmd
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/golang/glog"
|
||||
|
@ -29,6 +30,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
|
@ -40,6 +42,9 @@ import (
|
|||
|
||||
// AnnotateOptions have the data required to perform the annotate operation
|
||||
type AnnotateOptions struct {
|
||||
PrintFlags *printers.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
// Filename options
|
||||
resource.FilenameOptions
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
|
@ -99,10 +104,11 @@ var (
|
|||
|
||||
func NewAnnotateOptions(ioStreams genericclioptions.IOStreams) *AnnotateOptions {
|
||||
return &AnnotateOptions{
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
PrintFlags: printers.NewPrintFlags("annotated"),
|
||||
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
IOStreams: ioStreams,
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,8 +137,8 @@ func NewCmdAnnotate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *c
|
|||
|
||||
// bind flag structs
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
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.")
|
||||
|
@ -159,6 +165,17 @@ func (o *AnnotateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
|
|||
o.outputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
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 runtime.Object, out io.Writer) error {
|
||||
return printer.PrintObj(obj, out)
|
||||
}
|
||||
|
||||
// retrieves resource and annotation args from args
|
||||
// also checks args to verify that all resources are specified before annotations
|
||||
resources, annotationArgs, err := cmdutil.GetResourcesAndPairs(args, "annotation")
|
||||
|
@ -280,11 +297,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)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,13 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
|
@ -27,9 +32,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -48,22 +51,46 @@ var (
|
|||
)
|
||||
|
||||
type AutoscaleOptions struct {
|
||||
FilenameOptions resource.FilenameOptions
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
FilenameOptions *resource.FilenameOptions
|
||||
|
||||
Recorder genericclioptions.Recorder
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
Recorder genericclioptions.Recorder
|
||||
|
||||
PrintFlags *printers.PrintFlags
|
||||
ToPrinter func(string) (printers.ResourcePrinterFunc, error)
|
||||
|
||||
Builder *resource.Builder
|
||||
CanBeAutoscaled func(kind schema.GroupKind) error
|
||||
|
||||
CreateAnnotation bool
|
||||
DryRun bool
|
||||
EnforceNamespace bool
|
||||
|
||||
Mapper meta.RESTMapper
|
||||
Typer runtime.ObjectTyper
|
||||
ClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
|
||||
GeneratorFunc func(string, *meta.RESTMapping) (kubectl.StructuredGenerator, error)
|
||||
|
||||
Namespace string
|
||||
BuilderArgs []string
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewAutoscaleOptions() *AutoscaleOptions {
|
||||
func NewAutoscaleOptions(ioStreams genericclioptions.IOStreams) *AutoscaleOptions {
|
||||
return &AutoscaleOptions{
|
||||
FilenameOptions: resource.FilenameOptions{},
|
||||
PrintFlags: printers.NewPrintFlags("autoscaled"),
|
||||
FilenameOptions: &resource.FilenameOptions{},
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdAutoscale(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
o := NewAutoscaleOptions()
|
||||
func NewCmdAutoscale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewAutoscaleOptions(ioStreams)
|
||||
|
||||
validArgs := []string{"deployment", "replicaset", "replicationcontroller"}
|
||||
argAliases := kubectl.ResourceAliases(validArgs)
|
||||
|
@ -75,8 +102,9 @@ func NewCmdAutoscale(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||
Long: autoscaleLong,
|
||||
Example: autoscaleExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.RunAutoscale(f, out, cmd, args))
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate(cmd))
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: argAliases,
|
||||
|
@ -84,8 +112,8 @@ func NewCmdAutoscale(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||
|
||||
// bind flag structs
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
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.")
|
||||
|
@ -94,73 +122,105 @@ func NewCmdAutoscale(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||
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."))
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
usage := "identifying the resource to autoscale."
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, usage)
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
var err error
|
||||
|
||||
func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
o.DryRun = cmdutil.GetFlagBool(cmd, "dry-run")
|
||||
o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
|
||||
o.Builder = f.NewBuilder()
|
||||
o.CanBeAutoscaled = f.CanBeAutoscaled
|
||||
o.Mapper, o.Typer = f.Object()
|
||||
o.ClientForMapping = f.ClientForMapping
|
||||
o.BuilderArgs = args
|
||||
o.RecordFlags.Complete(f.Command(cmd, false))
|
||||
|
||||
var err error
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get the generator
|
||||
o.GeneratorFunc = func(name string, mapping *meta.RESTMapping) (kubectl.StructuredGenerator, error) {
|
||||
var generator kubectl.StructuredGenerator
|
||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
||||
case cmdutil.HorizontalPodAutoscalerV1GeneratorName:
|
||||
generator = &kubectl.HorizontalPodAutoscalerGeneratorV1{
|
||||
Name: name,
|
||||
MinReplicas: cmdutil.GetFlagInt32(cmd, "min"),
|
||||
MaxReplicas: cmdutil.GetFlagInt32(cmd, "max"),
|
||||
CPUPercent: cmdutil.GetFlagInt32(cmd, "cpu-percent"),
|
||||
ScaleRefName: name,
|
||||
ScaleRefKind: mapping.GroupVersionKind.Kind,
|
||||
ScaleRefApiVersion: mapping.GroupVersionKind.GroupVersion().String(),
|
||||
}
|
||||
default:
|
||||
return nil, cmdutil.UsageErrorf(cmd, "Generator %s not supported. ", generatorName)
|
||||
}
|
||||
|
||||
return generator, nil
|
||||
}
|
||||
|
||||
o.Namespace, o.EnforceNamespace, err = f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *AutoscaleOptions) Validate(cmd *cobra.Command) error {
|
||||
if err := validateFlags(cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *AutoscaleOptions) RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
||||
namespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// validate flags
|
||||
if err := validateFlags(cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := f.NewBuilder().
|
||||
func (o *AutoscaleOptions) Run() error {
|
||||
r := o.Builder.
|
||||
Internal().
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
ResourceTypeOrNameArgs(false, args...).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
FilenameParam(o.EnforceNamespace, o.FilenameOptions).
|
||||
ResourceTypeOrNameArgs(false, o.BuilderArgs...).
|
||||
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 cmdutil.UsageErrorf(cmd, "Generator %s not supported. ", generatorName)
|
||||
generator, err := o.GeneratorFunc(info.Name, mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate new object
|
||||
|
@ -169,11 +229,10 @@ func (o *AutoscaleOptions) RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *c
|
|||
return err
|
||||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
resourceMapper := &resource.Mapper{
|
||||
ObjectTyper: typer,
|
||||
RESTMapper: mapper,
|
||||
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
|
||||
ObjectTyper: o.Typer,
|
||||
RESTMapper: o.Mapper,
|
||||
ClientMapper: resource.ClientMapperFunc(o.ClientForMapping),
|
||||
Decoder: cmdutil.InternalVersionDecoder(),
|
||||
}
|
||||
hpa, err := resourceMapper.InfoForObject(object, nil)
|
||||
|
@ -183,26 +242,33 @@ func (o *AutoscaleOptions) RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *c
|
|||
if err := o.Recorder.Record(hpa.Object); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
if cmdutil.GetDryRunFlag(cmd) {
|
||||
return cmdutil.PrintObject(cmd, object, out)
|
||||
object = hpa.Object
|
||||
|
||||
if o.DryRun {
|
||||
count++
|
||||
|
||||
printer, err := o.ToPrinter("created")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printer.PrintObj(hpa.AsVersioned(), o.Out)
|
||||
}
|
||||
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), hpa.Object, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
if err := kubectl.CreateOrUpdateAnnotation(o.CreateAnnotation, hpa.Object, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
object, err = resource.NewHelper(hpa.Client, hpa.Mapping).Create(namespace, false, object)
|
||||
_, err = resource.NewHelper(hpa.Client, hpa.Mapping).Create(o.Namespace, false, object)
|
||||
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(info.AsVersioned(), o.Out)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -21,16 +21,20 @@ import (
|
|||
"io"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"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/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
|
||||
"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 +45,58 @@ 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 *printers.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
csrNames []string
|
||||
outputStyle string
|
||||
|
||||
clientSetFunc func() (internalclientset.Interface, error)
|
||||
builderFunc func() *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.builderFunc = f.NewBuilder
|
||||
o.clientSetFunc = f.ClientSet
|
||||
|
||||
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: printers.NewPrintFlags("approved"),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "approve (-f FILENAME | NAME)",
|
||||
DisableFlagsInUseLine: true,
|
||||
|
@ -85,9 +114,9 @@ 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.GetFlagBool(cmd, "force")))
|
||||
cmdutil.CheckErr(options.RunCertificateApprove(cmdutil.GetFlagBool(cmd, "force")))
|
||||
},
|
||||
}
|
||||
cmd.Flags().Bool("force", false, "Update the CSR even if it is already approved.")
|
||||
|
@ -97,8 +126,8 @@ func NewCmdCertificateApprove(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
func (options *CertificateOptions) RunCertificateApprove(f cmdutil.Factory, out io.Writer, force bool) error {
|
||||
return options.modifyCertificateCondition(f, out, force, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool, string) {
|
||||
func (o *CertificateOptions) RunCertificateApprove(force bool) error {
|
||||
return o.modifyCertificateCondition(o.builderFunc, o.clientSetFunc, force, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool) {
|
||||
var alreadyApproved bool
|
||||
for _, c := range csr.Status.Conditions {
|
||||
if c.Type == certificates.CertificateApproved {
|
||||
|
@ -106,7 +135,7 @@ func (options *CertificateOptions) RunCertificateApprove(f cmdutil.Factory, out
|
|||
}
|
||||
}
|
||||
if alreadyApproved {
|
||||
return csr, true, "approved"
|
||||
return csr, true
|
||||
}
|
||||
csr.Status.Conditions = append(csr.Status.Conditions, certificates.CertificateSigningRequestCondition{
|
||||
Type: certificates.CertificateApproved,
|
||||
|
@ -114,12 +143,15 @@ func (options *CertificateOptions) RunCertificateApprove(f cmdutil.Factory, out
|
|||
Message: "This CSR was approved by kubectl certificate approve.",
|
||||
LastUpdateTime: metav1.Now(),
|
||||
})
|
||||
return csr, false, "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: printers.NewPrintFlags("denied"),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "deny (-f FILENAME | NAME)",
|
||||
DisableFlagsInUseLine: true,
|
||||
|
@ -132,9 +164,9 @@ 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.GetFlagBool(cmd, "force")))
|
||||
cmdutil.CheckErr(options.RunCertificateDeny(cmdutil.GetFlagBool(cmd, "force")))
|
||||
},
|
||||
}
|
||||
cmd.Flags().Bool("force", false, "Update the CSR even if it is already denied.")
|
||||
|
@ -144,8 +176,8 @@ func NewCmdCertificateDeny(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
func (options *CertificateOptions) RunCertificateDeny(f cmdutil.Factory, out io.Writer, force bool) error {
|
||||
return options.modifyCertificateCondition(f, out, force, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool, string) {
|
||||
func (o *CertificateOptions) RunCertificateDeny(force bool) error {
|
||||
return o.modifyCertificateCondition(o.builderFunc, o.clientSetFunc, force, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool) {
|
||||
var alreadyDenied bool
|
||||
for _, c := range csr.Status.Conditions {
|
||||
if c.Type == certificates.CertificateDenied {
|
||||
|
@ -153,7 +185,7 @@ func (options *CertificateOptions) RunCertificateDeny(f cmdutil.Factory, out io.
|
|||
}
|
||||
}
|
||||
if alreadyDenied {
|
||||
return csr, true, "denied"
|
||||
return csr, true
|
||||
}
|
||||
csr.Status.Conditions = append(csr.Status.Conditions, certificates.CertificateSigningRequestCondition{
|
||||
Type: certificates.CertificateDenied,
|
||||
|
@ -161,17 +193,17 @@ func (options *CertificateOptions) RunCertificateDeny(f cmdutil.Factory, out io.
|
|||
Message: "This CSR was approved by kubectl certificate deny.",
|
||||
LastUpdateTime: metav1.Now(),
|
||||
})
|
||||
return csr, false, "denied"
|
||||
return csr, false
|
||||
})
|
||||
}
|
||||
|
||||
func (options *CertificateOptions) modifyCertificateCondition(f cmdutil.Factory, out io.Writer, force bool, modify func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool, string)) error {
|
||||
func (options *CertificateOptions) modifyCertificateCondition(builderFunc func() *resource.Builder, clientSetFunc func() (internalclientset.Interface, error), force bool, modify func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool)) error {
|
||||
var found int
|
||||
c, err := f.ClientSet()
|
||||
c, err := clientSetFunc()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r := f.NewBuilder().
|
||||
r := builderFunc().
|
||||
Internal().
|
||||
ContinueOnError().
|
||||
FilenameParam(false, &options.FilenameOptions).
|
||||
|
@ -185,7 +217,7 @@ func (options *CertificateOptions) modifyCertificateCondition(f cmdutil.Factory,
|
|||
return err
|
||||
}
|
||||
csr := info.Object.(*certificates.CertificateSigningRequest)
|
||||
csr, hasCondition, verb := modify(csr)
|
||||
csr, hasCondition := modify(csr)
|
||||
if !hasCondition || force {
|
||||
csr, err = c.Certificates().
|
||||
CertificateSigningRequests().
|
||||
|
@ -195,11 +227,11 @@ func (options *CertificateOptions) modifyCertificateCondition(f cmdutil.Factory,
|
|||
}
|
||||
}
|
||||
found++
|
||||
cmdutil.PrintSuccess(options.outputStyle == "name", out, info.Object, false, verb)
|
||||
return nil
|
||||
|
||||
return options.PrintObj(info.AsVersioned(), options.Out)
|
||||
})
|
||||
if found == 0 {
|
||||
fmt.Fprintf(out, "No resources found\n")
|
||||
fmt.Fprintf(options.Out, "No resources found\n")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -23,9 +23,11 @@ import (
|
|||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
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/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
|
||||
|
@ -43,41 +45,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())
|
||||
},
|
||||
}
|
||||
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.ClientConfig()
|
||||
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().
|
||||
b := o.Builder.
|
||||
Internal().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
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
|
||||
}
|
||||
|
@ -109,10 +132,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"
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -120,11 +143,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
|
||||
|
|
|
@ -28,19 +28,34 @@ 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/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
type ClusterInfoDumpOptions struct {
|
||||
PrintFlags *printers.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
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: printers.NewPrintFlags(""),
|
||||
|
||||
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())
|
||||
cmdutil.CheckErr(o.Run(f, cmd))
|
||||
},
|
||||
}
|
||||
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"))
|
||||
|
@ -88,7 +103,20 @@ func setupOutputWriter(cmd *cobra.Command, defaultWriter io.Writer, filename str
|
|||
return file
|
||||
}
|
||||
|
||||
func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error {
|
||||
func (o *ClusterInfoDumpOptions) Complete() error {
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonOutputFmt := "json"
|
||||
o.PrintFlags.OutputFormat = &jsonOutputFmt
|
||||
o.PrintObj = printer.PrintObj
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ClusterInfoDumpOptions) Run(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
timeout, err := cmdutil.GetPodRunningTimeoutFlag(cmd)
|
||||
if err != nil {
|
||||
return cmdutil.UsageErrorf(cmd, err.Error())
|
||||
|
@ -99,14 +127,12 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||
return err
|
||||
}
|
||||
|
||||
printer := &printers.JSONPrinter{}
|
||||
|
||||
nodes, err := 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(cmd, o.Out, "nodes.json")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -139,7 +165,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||
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(cmd, o.Out, path.Join(namespace, "events.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -147,7 +173,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||
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(cmd, o.Out, path.Join(namespace, "replication-controllers.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -155,7 +181,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||
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(cmd, o.Out, path.Join(namespace, "services.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -163,7 +189,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||
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(cmd, o.Out, path.Join(namespace, "daemonsets.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -171,7 +197,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||
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(cmd, o.Out, path.Join(namespace, "deployments.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -179,7 +205,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||
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(cmd, o.Out, path.Join(namespace, "replicasets.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -188,7 +214,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||
return err
|
||||
}
|
||||
|
||||
if err := printer.PrintObj(pods, setupOutputWriter(cmd, out, path.Join(namespace, "pods.json"))); err != nil {
|
||||
if err := o.PrintObj(pods, setupOutputWriter(cmd, o.Out, path.Join(namespace, "pods.json"))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -215,7 +241,7 @@ 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(cmd, o.Out, path.Join(namespace, pod.Name, "logs.txt"))
|
||||
|
||||
for i := range containers {
|
||||
printContainer(writer, containers[i], pod)
|
||||
|
@ -227,7 +253,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||
dir = "standard output"
|
||||
}
|
||||
if dir != "-" {
|
||||
fmt.Fprintf(out, "Cluster info dumped to %s\n", dir)
|
||||
fmt.Fprintf(o.Out, "Cluster info dumped to %s\n", dir)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"testing"
|
||||
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
func TestSetupOutputWriterNoOp(t *testing.T) {
|
||||
|
@ -33,7 +34,7 @@ func TestSetupOutputWriterNoOp(t *testing.T) {
|
|||
f := cmdtesting.NewTestFactory()
|
||||
defer f.Cleanup()
|
||||
|
||||
cmd := NewCmdClusterInfoDump(f, os.Stdout)
|
||||
cmd := NewCmdClusterInfoDump(f, genericclioptions.IOStreams{Out: os.Stdout, ErrOut: os.Stderr})
|
||||
cmd.Flag("output-directory").Value.Set(test)
|
||||
writer := setupOutputWriter(cmd, out, "/some/file/that/should/be/ignored")
|
||||
if writer != out {
|
||||
|
@ -55,7 +56,7 @@ func TestSetupOutputWriterFile(t *testing.T) {
|
|||
f := cmdtesting.NewTestFactory()
|
||||
defer f.Cleanup()
|
||||
|
||||
cmd := NewCmdClusterInfoDump(f, os.Stdout)
|
||||
cmd := NewCmdClusterInfoDump(f, genericclioptions.IOStreams{Out: os.Stdout, ErrOut: os.Stderr})
|
||||
cmd.Flag("output-directory").Value.Set(dir)
|
||||
writer := setupOutputWriter(cmd, out, file)
|
||||
if writer == out {
|
||||
|
|
|
@ -276,18 +276,18 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
|
|||
rollout.NewCmdRollout(f, out, err),
|
||||
NewCmdRollingUpdate(f, out),
|
||||
NewCmdScale(f, out, err),
|
||||
NewCmdAutoscale(f, out),
|
||||
NewCmdAutoscale(f, ioStreams),
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "Cluster Management Commands:",
|
||||
Commands: []*cobra.Command{
|
||||
NewCmdCertificate(f, out),
|
||||
NewCmdClusterInfo(f, out),
|
||||
NewCmdCertificate(f, ioStreams),
|
||||
NewCmdClusterInfo(f, ioStreams),
|
||||
NewCmdTop(f, out, err),
|
||||
NewCmdCordon(f, out),
|
||||
NewCmdUncordon(f, out),
|
||||
NewCmdDrain(f, out, err),
|
||||
NewCmdCordon(f, ioStreams),
|
||||
NewCmdUncordon(f, ioStreams),
|
||||
NewCmdDrain(f, ioStreams),
|
||||
NewCmdTaint(f, out),
|
||||
},
|
||||
},
|
||||
|
@ -300,7 +300,7 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
|
|||
NewCmdExec(f, in, out, err),
|
||||
NewCmdPortForward(f, out, err),
|
||||
NewCmdProxy(f, out),
|
||||
NewCmdCp(f, out, err),
|
||||
NewCmdCp(f, ioStreams),
|
||||
auth.NewCmdAuth(f, out, err),
|
||||
},
|
||||
},
|
||||
|
@ -310,13 +310,13 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
|
|||
NewCmdApply("kubectl", f, ioStreams),
|
||||
NewCmdPatch(f, out),
|
||||
NewCmdReplace(f, out, err),
|
||||
NewCmdConvert(f, out),
|
||||
NewCmdConvert(f, ioStreams),
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "Settings Commands:",
|
||||
Commands: []*cobra.Command{
|
||||
NewCmdLabel(f, out, err),
|
||||
NewCmdLabel(f, ioStreams),
|
||||
NewCmdAnnotate(f, ioStreams),
|
||||
NewCmdCompletion(out, ""),
|
||||
},
|
||||
|
|
|
@ -18,7 +18,6 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
@ -27,6 +26,7 @@ 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/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
|
@ -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 := NewConvertOptions()
|
||||
func NewCmdConvert(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := NewConvertOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "convert -f FILENAME",
|
||||
|
@ -71,18 +71,17 @@ 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", 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').)"))
|
||||
return cmd
|
||||
|
@ -90,19 +89,24 @@ func NewCmdConvert(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||
|
||||
// ConvertOptions have the data required to perform the convert operation
|
||||
type ConvertOptions struct {
|
||||
PrintFlags *printers.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
resource.FilenameOptions
|
||||
|
||||
builder *resource.Builder
|
||||
local bool
|
||||
|
||||
out io.Writer
|
||||
printer printers.ResourcePrinter
|
||||
|
||||
genericclioptions.IOStreams
|
||||
specifiedOutputVersion schema.GroupVersion
|
||||
}
|
||||
|
||||
func NewConvertOptions() *ConvertOptions {
|
||||
return &ConvertOptions{local: true}
|
||||
func NewConvertOptions(ioStreams genericclioptions.IOStreams) *ConvertOptions {
|
||||
return &ConvertOptions{
|
||||
PrintFlags: printers.NewPrintFlags("converted").WithDefaultOutput("yaml"),
|
||||
local: true,
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
// outputVersion returns the preferred output version for generic content (JSON, YAML, or templates)
|
||||
|
@ -117,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
|
||||
|
@ -145,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
|
||||
|
@ -189,10 +185,10 @@ func (o *ConvertOptions) RunConvert() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return o.printer.PrintObj(obj, 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
|
||||
|
|
|
@ -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",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -113,13 +107,13 @@ func TestConvertObject(t *testing.T) {
|
|||
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())
|
||||
}
|
||||
})
|
||||
|
|
|
@ -28,8 +28,11 @@ 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"
|
||||
|
||||
"github.com/renstrom/dedent"
|
||||
|
@ -61,8 +64,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,7 +91,8 @@ 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")
|
||||
|
@ -119,10 +141,35 @@ func extractFileSpec(arg string) (fileSpec, error) {
|
|||
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 {
|
||||
o.Container = cmdutil.GetFlagString(cmd, "container")
|
||||
|
||||
var err error
|
||||
o.Namespace, _, err = f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Clientset, err = f.ClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.ClientConfig, err = f.ClientConfig()
|
||||
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 {
|
||||
srcSpec, err := extractFileSpec(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -132,19 +179,19 @@ func runCopy(f cmdutil.Factory, cmd *cobra.Command, out, cmderr io.Writer, args
|
|||
return err
|
||||
}
|
||||
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{}),
|
||||
|
@ -158,10 +205,10 @@ 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 {
|
||||
func (o *CopyOptions) copyToPod(src, dest fileSpec) error {
|
||||
if len(src.File) == 0 || len(dest.File) == 0 {
|
||||
return errFileCannotBeEmpty
|
||||
}
|
||||
|
@ -172,7 +219,7 @@ func copyToPod(f cmdutil.Factory, cmd *cobra.Command, stdout, stderr io.Writer,
|
|||
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)
|
||||
|
@ -194,8 +241,8 @@ func copyToPod(f cmdutil.Factory, cmd *cobra.Command, stdout, stderr io.Writer,
|
|||
options := &ExecOptions{
|
||||
StreamOptions: StreamOptions{
|
||||
In: reader,
|
||||
Out: stdout,
|
||||
Err: stderr,
|
||||
Out: o.Out,
|
||||
Err: o.ErrOut,
|
||||
Stdin: true,
|
||||
|
||||
Namespace: dest.PodNamespace,
|
||||
|
@ -205,10 +252,10 @@ 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 {
|
||||
func (o *CopyOptions) copyFromPod(src, dest fileSpec) error {
|
||||
if len(src.File) == 0 || len(dest.File) == 0 {
|
||||
return errFileCannotBeEmpty
|
||||
}
|
||||
|
@ -218,7 +265,7 @@ func copyFromPod(f cmdutil.Factory, cmd *cobra.Command, cmderr io.Writer, src, d
|
|||
StreamOptions: StreamOptions{
|
||||
In: nil,
|
||||
Out: outStream,
|
||||
Err: cmderr,
|
||||
Err: o.Out,
|
||||
|
||||
Namespace: src.PodNamespace,
|
||||
PodName: src.PodName,
|
||||
|
@ -231,7 +278,7 @@ 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)
|
||||
|
@ -389,31 +436,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
|
||||
|
|
|
@ -36,6 +36,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"
|
||||
)
|
||||
|
||||
|
@ -526,7 +527,8 @@ func TestCopyToPod(t *testing.T) {
|
|||
tf.ClientConfigVal = defaultClientConfig()
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCp(tf, buf, errBuf)
|
||||
|
||||
cmd := NewCmdCp(tf, genericclioptions.IOStreams{Out: buf, ErrOut: errBuf})
|
||||
|
||||
srcFile, err := ioutil.TempDir("", "test")
|
||||
if err != nil {
|
||||
|
@ -554,6 +556,7 @@ func TestCopyToPod(t *testing.T) {
|
|||
}
|
||||
|
||||
for name, test := range tests {
|
||||
opts := NewCopyOptions(genericclioptions.IOStreams{Out: buf, ErrOut: errBuf})
|
||||
src := fileSpec{
|
||||
File: srcFile,
|
||||
}
|
||||
|
@ -562,8 +565,9 @@ func TestCopyToPod(t *testing.T) {
|
|||
PodName: "pod-name",
|
||||
File: test.dest,
|
||||
}
|
||||
opts.Complete(tf, cmd)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
err = copyToPod(tf, cmd, buf, errBuf, src, dest)
|
||||
err = opts.copyToPod(src, dest)
|
||||
//If error is NotFound error , it indicates that the
|
||||
//request has been sent correctly.
|
||||
//Treat this as no error.
|
||||
|
|
|
@ -19,7 +19,6 @@ package cmd
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -42,18 +41,23 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
|
||||
"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/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
type DrainOptions struct {
|
||||
PrintFlags *printers.PrintFlags
|
||||
ToPrinter func(string) (printers.ResourcePrinterFunc, error)
|
||||
|
||||
Namespace string
|
||||
client kubernetes.Interface
|
||||
restClient *restclient.RESTClient
|
||||
Factory cmdutil.Factory
|
||||
Force bool
|
||||
DryRun bool
|
||||
GracePeriodSeconds int
|
||||
|
@ -65,9 +69,9 @@ type DrainOptions struct {
|
|||
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: printers.NewPrintFlags("cordoned"),
|
||||
|
||||
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: printers.NewPrintFlags("uncordoned"),
|
||||
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,18 +193,18 @@ var (
|
|||
$ kubectl drain foo --grace-period=900`))
|
||||
)
|
||||
|
||||
func NewDrainOptions(f cmdutil.Factory, out, errOut io.Writer) *DrainOptions {
|
||||
func NewDrainOptions(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *DrainOptions {
|
||||
return &DrainOptions{
|
||||
Factory: f,
|
||||
Out: out,
|
||||
ErrOut: errOut,
|
||||
PrintFlags: printers.NewPrintFlags("drained"),
|
||||
|
||||
IOStreams: ioStreams,
|
||||
backOff: clockwork.NewRealClock(),
|
||||
GracePeriodSeconds: -1,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdDrain(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
options := NewDrainOptions(f, out, errOut)
|
||||
func NewCmdDrain(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := NewDrainOptions(f, ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "drain NODE",
|
||||
|
@ -202,7 +213,7 @@ 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())
|
||||
},
|
||||
}
|
||||
|
@ -218,9 +229,9 @@ 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
|
||||
|
||||
if len(args) == 0 && !cmd.Flags().Changed("selector") {
|
||||
|
@ -235,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
|
||||
}
|
||||
|
||||
|
@ -245,21 +256,34 @@ 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.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
builder := o.Factory.NewBuilder().
|
||||
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().
|
||||
Internal().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
ResourceNames("nodes", args...).
|
||||
SingleResourceType().
|
||||
Flatten()
|
||||
|
@ -294,6 +318,11 @@ func (o *DrainOptions) RunDrain() error {
|
|||
return err
|
||||
}
|
||||
|
||||
printer, err := o.ToPrinter("drained")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
drainedNodes := sets.NewString()
|
||||
var fatal error
|
||||
|
||||
|
@ -304,7 +333,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")
|
||||
printer.PrintObj(info.Object, o.Out)
|
||||
} else {
|
||||
fmt.Fprintf(o.ErrOut, "error: unable to drain node %q, aborting command...\n\n", info.Name)
|
||||
remainingNodes := []string{}
|
||||
|
@ -620,12 +649,17 @@ func (o *DrainOptions) waitForDelete(pods []corev1.Pod, interval, timeout time.D
|
|||
} else {
|
||||
verbStr = "deleted"
|
||||
}
|
||||
err := wait.PollImmediate(interval, timeout, func() (bool, error) {
|
||||
printer, 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)
|
||||
printer.PrintObj(&pod, o.Out)
|
||||
continue
|
||||
} else if err != nil {
|
||||
return false, err
|
||||
|
@ -677,11 +711,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
|
||||
|
@ -706,7 +735,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))
|
||||
printer, err := o.ToPrinter(already(desired))
|
||||
if err != nil {
|
||||
fmt.Printf("error: %v", err)
|
||||
continue
|
||||
}
|
||||
printer.PrintObj(nodeInfo.AsVersioned(), o.Out)
|
||||
} else {
|
||||
if !o.DryRun {
|
||||
helper := resource.NewHelper(o.restClient, nodeInfo.Mapping)
|
||||
|
@ -721,16 +755,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))
|
||||
printer, err := o.ToPrinter(changed(desired))
|
||||
if err != nil {
|
||||
fmt.Fprintf(o.ErrOut, "%v", err)
|
||||
continue
|
||||
}
|
||||
printer.PrintObj(nodeInfo.AsVersioned(), o.Out)
|
||||
}
|
||||
} else {
|
||||
cmdutil.PrintSuccess(false, o.Out, nodeInfo.Object, o.DryRun, "skipped")
|
||||
printer, err := o.ToPrinter("skipped")
|
||||
if err != nil {
|
||||
fmt.Fprintf(o.ErrOut, "%v", err)
|
||||
continue
|
||||
}
|
||||
printer.PrintObj(nodeInfo.AsVersioned(), o.Out)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,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"
|
||||
|
@ -51,6 +52,7 @@ import (
|
|||
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"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -84,7 +86,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
|
||||
}{
|
||||
|
@ -197,7 +199,7 @@ func TestCordon(t *testing.T) {
|
|||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := test.cmd(tf, buf)
|
||||
cmd := test.cmd(tf, genericclioptions.IOStreams{Out: buf, ErrOut: buf})
|
||||
|
||||
saw_fatal := false
|
||||
func() {
|
||||
|
@ -708,7 +710,7 @@ func TestDrain(t *testing.T) {
|
|||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdDrain(tf, buf, errBuf)
|
||||
cmd := NewCmdDrain(tf, genericclioptions.IOStreams{Out: buf, ErrOut: errBuf})
|
||||
|
||||
saw_fatal := false
|
||||
fatal_msg := ""
|
||||
|
@ -833,9 +835,18 @@ func TestDeletePods(t *testing.T) {
|
|||
tf := cmdtesting.NewTestFactory()
|
||||
defer tf.Cleanup()
|
||||
|
||||
o := DrainOptions{Factory: tf}
|
||||
o := DrainOptions{
|
||||
PrintFlags: printers.NewPrintFlags("drained"),
|
||||
}
|
||||
o.mapper, _ = tf.Object()
|
||||
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)
|
||||
|
||||
|
|
|
@ -94,11 +94,11 @@ func NewCmdEdit(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra
|
|||
|
||||
// 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().StringVarP(&o.Output, "output", "o", o.Output, "Output format. One of: yaml|json.")
|
||||
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.")
|
||||
|
|
|
@ -20,10 +20,12 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
|
@ -31,6 +33,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -76,17 +79,37 @@ var (
|
|||
type ExposeServiceOptions struct {
|
||||
FilenameOptions resource.FilenameOptions
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
PrintFlags *printers.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
DryRun bool
|
||||
EnforceNamespace bool
|
||||
|
||||
Generators func(string) map[string]kubectl.Generator
|
||||
CanBeExposed func(kind schema.GroupKind) error
|
||||
ClientForMapping func(*meta.RESTMapping) (resource.RESTClient, error)
|
||||
MapBasedSelectorForObject func(runtime.Object) (string, error)
|
||||
PortsForObject func(runtime.Object) ([]string, error)
|
||||
ProtocolsForObject func(runtime.Object) (map[string]string, error)
|
||||
LabelsForObject func(runtime.Object) (map[string]string, error)
|
||||
|
||||
Namespace string
|
||||
Mapper meta.RESTMapper
|
||||
Typer runtime.ObjectTyper
|
||||
|
||||
Builder *resource.Builder
|
||||
|
||||
Recorder genericclioptions.Recorder
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
func NewExposeServiceOptions(streams genericclioptions.IOStreams) *ExposeServiceOptions {
|
||||
func NewExposeServiceOptions(ioStreams genericclioptions.IOStreams) *ExposeServiceOptions {
|
||||
return &ExposeServiceOptions{
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
PrintFlags: printers.NewPrintFlags("exposed"),
|
||||
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
IOStreams: streams,
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,15 +130,15 @@ func NewCmdExposeService(f cmdutil.Factory, streams genericclioptions.IOStreams)
|
|||
Example: exposeExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.RunExpose(f, cmd, args))
|
||||
cmdutil.CheckErr(o.RunExpose(cmd, args))
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
}
|
||||
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddPrinterFlags(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"))
|
||||
|
@ -140,7 +163,16 @@ func NewCmdExposeService(f cmdutil.Factory, streams genericclioptions.IOStreams)
|
|||
}
|
||||
|
||||
func (o *ExposeServiceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
var err 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(f.Command(cmd, false))
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
|
@ -148,32 +180,41 @@ func (o *ExposeServiceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) e
|
|||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
o.Generators = f.Generators
|
||||
o.Builder = f.NewBuilder()
|
||||
o.CanBeExposed = f.CanBeExposed
|
||||
o.ClientForMapping = f.ClientForMapping
|
||||
o.MapBasedSelectorForObject = f.MapBasedSelectorForObject
|
||||
o.PortsForObject = f.PortsForObject
|
||||
o.ProtocolsForObject = f.ProtocolsForObject
|
||||
o.Mapper, o.Typer = f.Object()
|
||||
o.LabelsForObject = f.LabelsForObject
|
||||
|
||||
func (o *ExposeServiceOptions) RunExpose(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
namespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
o.Namespace, o.EnforceNamespace, err = f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
r := f.NewBuilder().
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *ExposeServiceOptions) RunExpose(cmd *cobra.Command, args []string) error {
|
||||
r := o.Builder.
|
||||
Internal().
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
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)
|
||||
|
@ -186,7 +227,7 @@ func (o *ExposeServiceOptions) RunExpose(f cmdutil.Factory, cmd *cobra.Command,
|
|||
}
|
||||
|
||||
mapping := info.ResourceMapping()
|
||||
if err := f.CanBeExposed(mapping.GroupVersionKind.GroupKind()); err != nil {
|
||||
if err := o.CanBeExposed(mapping.GroupVersionKind.GroupKind()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -200,7 +241,7 @@ func (o *ExposeServiceOptions) RunExpose(f cmdutil.Factory, cmd *cobra.Command,
|
|||
// 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)
|
||||
}
|
||||
|
@ -212,7 +253,7 @@ func (o *ExposeServiceOptions) RunExpose(f cmdutil.Factory, cmd *cobra.Command,
|
|||
// 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)
|
||||
}
|
||||
|
@ -231,7 +272,7 @@ func (o *ExposeServiceOptions) RunExpose(f cmdutil.Factory, cmd *cobra.Command,
|
|||
// 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)
|
||||
}
|
||||
|
@ -241,7 +282,7 @@ func (o *ExposeServiceOptions) RunExpose(f cmdutil.Factory, cmd *cobra.Command,
|
|||
}
|
||||
|
||||
if kubectl.IsZero(params["labels"]) {
|
||||
labels, err := f.LabelsForObject(info.Object)
|
||||
labels, err := o.LabelsForObject(info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -270,9 +311,9 @@ func (o *ExposeServiceOptions) RunExpose(f cmdutil.Factory, cmd *cobra.Command,
|
|||
}
|
||||
|
||||
resourceMapper := &resource.Mapper{
|
||||
ObjectTyper: typer,
|
||||
RESTMapper: mapper,
|
||||
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
|
||||
ObjectTyper: o.Typer,
|
||||
RESTMapper: o.Mapper,
|
||||
ClientMapper: resource.ClientMapperFunc(o.ClientForMapping),
|
||||
Decoder: cmdutil.InternalVersionDecoder(),
|
||||
}
|
||||
info, err = resourceMapper.InfoForObject(object, nil)
|
||||
|
@ -283,29 +324,20 @@ func (o *ExposeServiceOptions) RunExpose(f cmdutil.Factory, cmd *cobra.Command,
|
|||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
info.Refresh(object, true)
|
||||
if cmdutil.GetDryRunFlag(cmd) {
|
||||
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
|
||||
return cmdutil.PrintObject(cmd, object, o.Out)
|
||||
}
|
||||
cmdutil.PrintSuccess(false, o.Out, info.Object, true, "exposed")
|
||||
return nil
|
||||
if o.DryRun {
|
||||
return o.PrintObj(object, o.Out)
|
||||
}
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info.Object, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Serialize the object with the annotation applied.
|
||||
object, err = resource.NewHelper(info.Client, info.Mapping).Create(namespace, false, object)
|
||||
object, err = resource.NewHelper(info.Client, info.Mapping).Create(o.Namespace, false, object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
|
||||
return cmdutil.PrintObject(cmd, object, o.Out)
|
||||
}
|
||||
|
||||
cmdutil.PrintSuccess(false, o.Out, info.Object, false, "exposed")
|
||||
return nil
|
||||
return o.PrintObj(info.AsVersioned(), o.Out)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
{
|
||||
|
@ -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,
|
||||
},
|
||||
{
|
||||
|
@ -500,7 +500,7 @@ func TestRunExposeService(t *testing.T) {
|
|||
|
||||
out := buf.String()
|
||||
if _, ok := test.flags["dry-run"]; ok {
|
||||
test.expected = fmt.Sprintf("service %q exposed (dry run)", test.flags["name"])
|
||||
test.expected = fmt.Sprintf("service/%s exposed (dry run)", test.flags["name"])
|
||||
}
|
||||
|
||||
if !strings.Contains(out, test.expected) {
|
||||
|
|
|
@ -18,7 +18,6 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
|
@ -40,6 +39,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
// LabelOptions have the data required to perform the label operation
|
||||
|
@ -48,6 +48,9 @@ type LabelOptions struct {
|
|||
resource.FilenameOptions
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
|
||||
PrintFlags *printers.PrintFlags
|
||||
ToPrinter func(string) (printers.ResourcePrinterFunc, error)
|
||||
|
||||
// Common user flags
|
||||
overwrite bool
|
||||
list bool
|
||||
|
@ -66,8 +69,7 @@ type LabelOptions struct {
|
|||
Recorder genericclioptions.Recorder
|
||||
|
||||
// Common shared fields
|
||||
out io.Writer
|
||||
errout io.Writer
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -100,19 +102,19 @@ var (
|
|||
kubectl label pods foo bar-`))
|
||||
)
|
||||
|
||||
func NewLabelOptions(out, errOut io.Writer) *LabelOptions {
|
||||
func NewLabelOptions(ioStreams genericclioptions.IOStreams) *LabelOptions {
|
||||
return &LabelOptions{
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
PrintFlags: printers.NewPrintFlags("labeled"),
|
||||
|
||||
out: out,
|
||||
errout: errOut,
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdLabel(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
o := NewLabelOptions(out, errOut)
|
||||
func NewCmdLabel(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewLabelOptions(ioStreams)
|
||||
|
||||
validArgs := cmdutil.ValidArgList(f)
|
||||
|
||||
|
@ -136,8 +138,8 @@ func NewCmdLabel(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
|||
}
|
||||
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddPrinterFlags(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.")
|
||||
|
@ -165,6 +167,19 @@ func (o *LabelOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
|
|||
o.outputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
o.dryrun = cmdutil.GetDryRunFlag(cmd)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
resources, labelArgs, err := cmdutil.GetResourcesAndPairs(args, "label")
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -255,7 +270,7 @@ 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,19 +319,20 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
|
|||
indent := ""
|
||||
if !one {
|
||||
indent = " "
|
||||
fmt.Fprintf(o.errout, "Listing labels for %s.%s/%s:\n", info.Mapping.GroupVersionKind.Kind, info.Mapping.GroupVersionKind.Group, info.Name)
|
||||
fmt.Fprintf(o.ErrOut, "Listing labels for %s.%s/%s:\n", info.Mapping.GroupVersionKind.Kind, info.Mapping.GroupVersionKind.Group, info.Name)
|
||||
}
|
||||
for k, v := range accessor.GetLabels() {
|
||||
fmt.Fprintf(o.out, "%s%s=%s\n", indent, 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.AsVersioned(), o.Out)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
|
@ -29,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"
|
||||
)
|
||||
|
||||
|
@ -328,13 +329,13 @@ func TestLabelErrors(t *testing.T) {
|
|||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdLabel(tf, buf, buf)
|
||||
cmd := NewCmdLabel(tf, genericclioptions.IOStreams{Out: buf, ErrOut: buf})
|
||||
cmd.SetOutput(buf)
|
||||
|
||||
for k, v := range testCase.flags {
|
||||
cmd.Flags().Set(k, v)
|
||||
}
|
||||
opts := NewLabelOptions(buf, buf)
|
||||
opts := NewLabelOptions(genericclioptions.IOStreams{Out: buf, ErrOut: buf})
|
||||
err := opts.Complete(tf, cmd, testCase.args)
|
||||
if err == nil {
|
||||
err = opts.Validate()
|
||||
|
@ -390,8 +391,8 @@ func TestLabelForResourceFromFile(t *testing.T) {
|
|||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdLabel(tf, buf, buf)
|
||||
opts := NewLabelOptions(buf, buf)
|
||||
cmd := NewCmdLabel(tf, genericclioptions.IOStreams{Out: buf, ErrOut: buf})
|
||||
opts := NewLabelOptions(genericclioptions.IOStreams{Out: buf, ErrOut: buf})
|
||||
opts.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
|
||||
err := opts.Complete(tf, cmd, []string{"a=b"})
|
||||
if err == nil {
|
||||
|
@ -423,8 +424,8 @@ func TestLabelLocal(t *testing.T) {
|
|||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdLabel(tf, buf, buf)
|
||||
opts := NewLabelOptions(buf, buf)
|
||||
cmd := NewCmdLabel(tf, genericclioptions.IOStreams{Out: buf, ErrOut: buf})
|
||||
opts := NewLabelOptions(genericclioptions.IOStreams{Out: buf, ErrOut: buf})
|
||||
opts.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
|
||||
opts.local = true
|
||||
err := opts.Complete(tf, cmd, []string{"a=b"})
|
||||
|
@ -481,9 +482,9 @@ func TestLabelMultipleObjects(t *testing.T) {
|
|||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
opts := NewLabelOptions(buf, buf)
|
||||
opts := NewLabelOptions(genericclioptions.IOStreams{Out: buf, ErrOut: buf})
|
||||
opts.all = true
|
||||
cmd := NewCmdLabel(tf, buf, buf)
|
||||
cmd := NewCmdLabel(tf, genericclioptions.IOStreams{Out: buf, ErrOut: buf})
|
||||
err := opts.Complete(tf, cmd, []string{"pods", "a=b"})
|
||||
if err == nil {
|
||||
err = opts.Validate()
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
|
@ -40,6 +40,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
var patchTypes = map[string]types.PatchType{"json": types.JSONPatchType, "merge": types.MergePatchType, "strategic": types.StrategicMergePatchType}
|
||||
|
@ -49,6 +50,8 @@ var patchTypes = map[string]types.PatchType{"json": types.JSONPatchType, "merge"
|
|||
type PatchOptions struct {
|
||||
resource.FilenameOptions
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
PrintFlags *printers.PrintFlags
|
||||
ToPrinter func(string) (printers.ResourcePrinterFunc, error)
|
||||
|
||||
Local bool
|
||||
DryRun bool
|
||||
|
@ -86,8 +89,8 @@ var (
|
|||
func NewPatchOptions() *PatchOptions {
|
||||
return &PatchOptions{
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
PrintFlags: printers.NewPrintFlags("patched"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,11 +113,11 @@ func NewCmdPatch(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||
}
|
||||
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmd.Flags().StringP("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.AddDryRunFlag(cmd)
|
||||
|
||||
usage := "identifying the resource to update"
|
||||
|
@ -137,6 +140,19 @@ func (o *PatchOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
|||
o.OutputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
o.DryRun = cmdutil.GetFlagBool(cmd, "dry-run")
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -222,10 +238,11 @@ func (o *PatchOptions) RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Com
|
|||
return err
|
||||
}
|
||||
|
||||
if len(o.OutputFormat) > 0 && o.OutputFormat != "name" {
|
||||
return cmdutil.PrintObject(cmd, info.Object, out)
|
||||
printer, err := o.ToPrinter(patchOperation(didPatch))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmdutil.PrintSuccess(o.OutputFormat == "name", out, info.Object, false, patchOperation(didPatch))
|
||||
printer.PrintObj(info.AsVersioned(), out)
|
||||
|
||||
// if object was not successfully patched, exit with error code 1
|
||||
if !didPatch {
|
||||
|
@ -264,12 +281,11 @@ func (o *PatchOptions) RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Com
|
|||
}
|
||||
}
|
||||
|
||||
if len(o.OutputFormat) > 0 && o.OutputFormat != "name" {
|
||||
return cmdutil.PrintObject(cmd, info.Object, out)
|
||||
printer, err := o.ToPrinter(patchOperation(didPatch))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmdutil.PrintSuccess(o.OutputFormat == "name", out, info.Object, o.DryRun, patchOperation(didPatch))
|
||||
return nil
|
||||
return printer.PrintObj(info.AsVersioned(), out)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -144,7 +144,7 @@ func TestPatchNoop(t *testing.T) {
|
|||
cmd.Flags().Set("namespace", "test")
|
||||
cmd.Flags().Set("patch", `{"metadata":{"annotations":{"foo":"bar"}}}`)
|
||||
cmd.Run(cmd, []string{"services", "frontend"})
|
||||
if buf.String() != "service \"baz\" patched\n" {
|
||||
if buf.String() != "service/baz patched\n" {
|
||||
t.Errorf("unexpected output: %s", buf.String())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ args:
|
|||
- service/svc1
|
||||
namespace: "myproject"
|
||||
expectedStdout:
|
||||
- configmap "cm1" edited
|
||||
- service "svc1" edited
|
||||
- configmap/cm1 edited
|
||||
- service/svc1 edited
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: request
|
||||
|
|
|
@ -5,8 +5,8 @@ args:
|
|||
- service/svc1
|
||||
namespace: "myproject"
|
||||
expectedStdout:
|
||||
- configmap "cm1" edited
|
||||
- service "svc1" edited
|
||||
- configmap/cm1 edited
|
||||
- service/svc1 edited
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: request
|
||||
|
|
|
@ -4,7 +4,7 @@ args:
|
|||
- service/svc1
|
||||
namespace: myproject
|
||||
expectedStdout:
|
||||
- "service \"svc1\" edited"
|
||||
- "service/svc1 edited"
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: request
|
||||
|
|
|
@ -6,7 +6,7 @@ args:
|
|||
outputFormat: yaml
|
||||
namespace: myproject
|
||||
expectedStdout:
|
||||
- service "svc1" edited
|
||||
- service/svc1 edited
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: request
|
||||
|
|
|
@ -3,7 +3,7 @@ mode: create
|
|||
filename: "svc.yaml"
|
||||
namespace: "edit-test"
|
||||
expectedStdout:
|
||||
- "service \"svc1\" created"
|
||||
- "service/svc1 created"
|
||||
expectedStderr:
|
||||
- "\"svc2\" is invalid"
|
||||
expectedExitCode: 1
|
||||
|
|
|
@ -3,8 +3,8 @@ mode: create
|
|||
filename: "svc.yaml"
|
||||
namespace: "edit-test"
|
||||
expectedStdout:
|
||||
- service "svc1" created
|
||||
- service "svc2" created
|
||||
- service/svc1 created
|
||||
- service/svc2 created
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: edit
|
||||
|
|
|
@ -5,7 +5,7 @@ args:
|
|||
- svc1
|
||||
namespace: edit-test
|
||||
expectedStdout:
|
||||
- service "svc1" edited
|
||||
- service/svc1 edited
|
||||
expectedStderr:
|
||||
- "error: services \"svc1\" is invalid"
|
||||
expectedExitCode: 0
|
||||
|
|
|
@ -11,7 +11,7 @@ outputPatch: "true"
|
|||
namespace: edit-test
|
||||
expectedStdout:
|
||||
- 'Patch: {"metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Service\",\"metadata\":{\"annotations\":{},\"creationTimestamp\":\"2017-02-27T19:40:53Z\",\"labels\":{\"app\":\"svc1\",\"new-label\":\"new-value\"},\"name\":\"svc1\",\"namespace\":\"edit-test\",\"resourceVersion\":\"670\",\"selfLink\":\"/api/v1/namespaces/edit-test/services/svc1\",\"uid\":\"a6c11186-fd24-11e6-b53c-480fcf4a5275\"},\"spec\":{\"clusterIP\":\"10.0.0.204\",\"ports\":[{\"name\":\"80\",\"port\":80,\"protocol\":\"TCP\",\"targetPort\":80}],\"selector\":{\"app\":\"svc1\"},\"sessionAffinity\":\"None\",\"type\":\"ClusterIP\"},\"status\":{\"loadBalancer\":{}}}\n"},"labels":{"new-label":"new-value"}}}'
|
||||
- service "svc1" edited
|
||||
- service/svc1 edited
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: request
|
||||
|
|
|
@ -4,8 +4,8 @@ args:
|
|||
- configmaps,services
|
||||
namespace: "edit-test"
|
||||
expectedStdout:
|
||||
- configmap "cm1" edited
|
||||
- service "svc1" edited
|
||||
- configmap/cm1 edited
|
||||
- service/svc1 edited
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: request
|
||||
|
|
|
@ -5,8 +5,8 @@ args:
|
|||
- service/svc1
|
||||
namespace: "edit-test"
|
||||
expectedStdout:
|
||||
- configmap "cm1" edited
|
||||
- service "svc1" edited
|
||||
- configmap/cm1 edited
|
||||
- service/svc1 edited
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: request
|
||||
|
|
|
@ -5,8 +5,8 @@ args:
|
|||
- service/svc1
|
||||
namespace: "edit-test"
|
||||
expectedStdout:
|
||||
- configmap "cm1" edited
|
||||
- service "svc1" edited
|
||||
- configmap/cm1 edited
|
||||
- service/svc1 edited
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: request
|
||||
|
|
|
@ -9,7 +9,7 @@ args:
|
|||
saveConfig: "false"
|
||||
namespace: edit-test
|
||||
expectedStdout:
|
||||
- service "svc1" edited
|
||||
- service/svc1 edited
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: request
|
||||
|
|
|
@ -6,9 +6,9 @@ args:
|
|||
- bars/test2
|
||||
namespace: default
|
||||
expectedStdout:
|
||||
- "service \"kubernetes\" edited"
|
||||
- "bar.company.com \"test\" edited"
|
||||
- "bar.company.com \"test2\" edited"
|
||||
- "service/kubernetes edited"
|
||||
- "bar.company.com/test edited"
|
||||
- "bar.company.com/test2 edited"
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: request
|
||||
|
|
|
@ -8,7 +8,7 @@ args:
|
|||
- svc1
|
||||
namespace: edit-test
|
||||
expectedStdout:
|
||||
- service "svc1" edited
|
||||
- service/svc1 edited
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: request
|
||||
|
|
|
@ -4,7 +4,7 @@ args:
|
|||
- service/kubernetes
|
||||
namespace: default
|
||||
expectedStdout:
|
||||
- "service \"kubernetes\" edited"
|
||||
- "service/kubernetes edited"
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: request
|
||||
|
|
|
@ -4,7 +4,7 @@ args:
|
|||
- storageclasses.v1beta1.storage.k8s.io/foo
|
||||
namespace: default
|
||||
expectedStdout:
|
||||
- "storageclass.storage.k8s.io \"foo\" edited"
|
||||
- "storageclass.storage.k8s.io/foo edited"
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: request
|
||||
|
|
|
@ -4,7 +4,7 @@ args:
|
|||
- storageclasses.v0.storage.k8s.io/foo
|
||||
namespace: default
|
||||
expectedStdout:
|
||||
- "storageclass.storage.k8s.io \"foo\" edited"
|
||||
- "storageclass.storage.k8s.io/foo edited"
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: request
|
||||
|
|
|
@ -9,7 +9,7 @@ args:
|
|||
saveConfig: "true"
|
||||
namespace: edit-test
|
||||
expectedStdout:
|
||||
- service "svc1" edited
|
||||
- service/svc1 edited
|
||||
expectedExitCode: 0
|
||||
steps:
|
||||
- type: request
|
||||
|
|
|
@ -57,6 +57,9 @@ type EditOptions struct {
|
|||
resource.FilenameOptions
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
|
||||
PrintFlags *printers.PrintFlags
|
||||
ToPrinter func(string) (printers.ResourcePrinterFunc, error)
|
||||
|
||||
Output string
|
||||
OutputPatch bool
|
||||
WindowsLineEndings bool
|
||||
|
@ -86,12 +89,14 @@ func NewEditOptions(editMode EditMode, ioStreams genericclioptions.IOStreams) *E
|
|||
|
||||
EditMode: editMode,
|
||||
|
||||
Output: "yaml",
|
||||
PrintFlags: printers.NewPrintFlags("edited"),
|
||||
|
||||
WindowsLineEndings: goruntime.GOOS == "windows",
|
||||
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
|
||||
IOStreams: ioStreams,
|
||||
Output: "yaml",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,6 +164,15 @@ func (o *EditOptions) Complete(f cmdutil.Factory, args []string, cmd *cobra.Comm
|
|||
Do()
|
||||
}
|
||||
|
||||
o.ToPrinter = func(operation string) (printers.ResourcePrinterFunc, error) {
|
||||
o.PrintFlags.NamePrintFlags.Operation = operation
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return printer.PrintObj, nil
|
||||
}
|
||||
|
||||
o.CmdNamespace = cmdNamespace
|
||||
o.f = f
|
||||
|
||||
|
@ -423,14 +437,23 @@ func (o *EditOptions) visitToApplyEditPatch(originalInfos []*resource.Info, patc
|
|||
}
|
||||
|
||||
if reflect.DeepEqual(originalJS, editedJS) {
|
||||
cmdutil.PrintSuccess(false, o.Out, info.Object, false, "skipped")
|
||||
printer, err := o.ToPrinter("skipped")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printer.PrintObj(info.AsVersioned(), o.Out)
|
||||
return nil
|
||||
} else {
|
||||
err := o.annotationPatch(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmdutil.PrintSuccess(false, o.Out, info.Object, false, "edited")
|
||||
|
||||
printer, err := o.ToPrinter("edited")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printer.PrintObj(info.AsVersioned(), o.Out)
|
||||
return nil
|
||||
}
|
||||
})
|
||||
|
@ -549,7 +572,11 @@ func (o *EditOptions) visitToPatch(originalInfos []*resource.Info, patchVisitor
|
|||
|
||||
if reflect.DeepEqual(originalJS, editedJS) {
|
||||
// no edit, so just skip it.
|
||||
cmdutil.PrintSuccess(false, o.Out, info.Object, false, "skipped")
|
||||
printer, err := o.ToPrinter("skipped")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printer.PrintObj(info.AsVersioned(), o.Out)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -603,7 +630,11 @@ func (o *EditOptions) visitToPatch(originalInfos []*resource.Info, patchVisitor
|
|||
return nil
|
||||
}
|
||||
info.Refresh(patched, true)
|
||||
cmdutil.PrintSuccess(false, o.Out, info.Object, false, "edited")
|
||||
printer, err := o.ToPrinter("edited")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printer.PrintObj(info.AsVersioned(), o.Out)
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
|
@ -614,7 +645,11 @@ func (o *EditOptions) visitToCreate(createVisitor resource.Visitor) error {
|
|||
if err := resource.CreateAndRefresh(info); err != nil {
|
||||
return err
|
||||
}
|
||||
cmdutil.PrintSuccess(false, o.Out, info.Object, false, "created")
|
||||
printer, err := o.ToPrinter("created")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printer.PrintObj(info.AsVersioned(), o.Out)
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
|
|
|
@ -79,6 +79,20 @@ func (f *PrintFlags) AddFlags(cmd *cobra.Command) {
|
|||
}
|
||||
}
|
||||
|
||||
// WithDefaultOutput sets a default output format if one is not provided through a flag value
|
||||
func (f *PrintFlags) WithDefaultOutput(output string) *PrintFlags {
|
||||
existingFormat := ""
|
||||
if f.OutputFormat != nil {
|
||||
existingFormat = *f.OutputFormat
|
||||
}
|
||||
if len(existingFormat) == 0 {
|
||||
existingFormat = output
|
||||
}
|
||||
f.OutputFormat = &existingFormat
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func NewPrintFlags(operation string) *PrintFlags {
|
||||
outputFormat := ""
|
||||
|
||||
|
|
Loading…
Reference in New Issue