mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 21:17:23 +00:00
Merge pull request #62820 from juanvallejo/jvallejo/wire-more-print-flags
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. wire printflags through additional cmds **Release note**: ```release-note NONE ``` Adds PrintFlag pattern to more commands. cc @deads2k @soltysh
This commit is contained in:
commit
acbccfba84
@ -693,7 +693,7 @@ run_pod_tests() {
|
|||||||
kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'valid-pod:'
|
kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'valid-pod:'
|
||||||
|
|
||||||
## Patch can modify a local object
|
## Patch can modify a local object
|
||||||
kubectl patch --local -f pkg/kubectl/validation/testdata/v1/validPod.yaml --patch='{"spec": {"restartPolicy":"Never"}}' -o jsonpath='{.spec.restartPolicy}' | grep -q "Never"
|
kubectl patch --local -f pkg/kubectl/validation/testdata/v1/validPod.yaml --patch='{"spec": {"restartPolicy":"Never"}}' -o yaml | grep -q "Never"
|
||||||
|
|
||||||
## Patch fails with error message "not patched" and exit code 1
|
## Patch fails with error message "not patched" and exit code 1
|
||||||
output_message=$(! kubectl patch "${kube_flags[@]}" pod valid-pod -p='{"spec":{"replicas":7}}' 2>&1)
|
output_message=$(! kubectl patch "${kube_flags[@]}" pod valid-pod -p='{"spec":{"replicas":7}}' 2>&1)
|
||||||
@ -2139,8 +2139,7 @@ run_recursive_resources_tests() {
|
|||||||
kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" 'nginx:'
|
kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" 'nginx:'
|
||||||
kube::test::get_object_assert deployment "{{range.items}}{{$image_field0}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
|
kube::test::get_object_assert deployment "{{range.items}}{{$image_field0}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
|
||||||
# Command
|
# Command
|
||||||
output_message=$(kubectl convert --local -f hack/testdata/deployment-revision1.yaml --output-version=apps/v1beta1 -o go-template='{{ .apiVersion }}' "${kube_flags[@]}")
|
output_message=$(kubectl convert --local -f hack/testdata/deployment-revision1.yaml --output-version=apps/v1beta1 -o yaml "${kube_flags[@]}")
|
||||||
echo $output_message
|
|
||||||
# Post-condition: apiVersion is still extensions/v1beta1 in the live deployment, but command output is the new value
|
# Post-condition: apiVersion is still extensions/v1beta1 in the live deployment, but command output is the new value
|
||||||
kube::test::get_object_assert 'deployment nginx' "{{ .apiVersion }}" 'extensions/v1beta1'
|
kube::test::get_object_assert 'deployment nginx' "{{ .apiVersion }}" 'extensions/v1beta1'
|
||||||
kube::test::if_has_string "${output_message}" "apps/v1beta1"
|
kube::test::if_has_string "${output_message}" "apps/v1beta1"
|
||||||
@ -2843,7 +2842,7 @@ run_rc_tests() {
|
|||||||
# Pre-condition: default run without --name flag; should succeed by truncating the inherited name
|
# 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[@]}")
|
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
|
# 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
|
# Clean-up
|
||||||
kubectl delete svc kubernetes-serve-hostname-testing-sixty-three-characters-in-len "${kube_flags[@]}"
|
kubectl delete svc kubernetes-serve-hostname-testing-sixty-three-characters-in-len "${kube_flags[@]}"
|
||||||
|
|
||||||
@ -2851,7 +2850,7 @@ run_rc_tests() {
|
|||||||
# Pre-condition: don't use --port flag
|
# 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[@]}")
|
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
|
# 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
|
# 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' "{{$port_name}} {{$port_field}}" 'port-1 2380'
|
||||||
kube::test::get_object_assert 'service etcd-server' "{{$second_port_name}} {{$second_port_field}}" 'port-2 2379'
|
kube::test::get_object_assert 'service etcd-server' "{{$second_port_name}} {{$second_port_field}}" 'port-2 2379'
|
||||||
@ -4647,7 +4646,7 @@ __EOF__
|
|||||||
kube::test::if_has_string "${response}" 'must provide one or more resources'
|
kube::test::if_has_string "${response}" 'must provide one or more resources'
|
||||||
# test=label matches our node
|
# test=label matches our node
|
||||||
response=$(kubectl cordon --selector test=label)
|
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
|
# invalid=label does not match any nodes
|
||||||
response=$(kubectl cordon --selector invalid=label)
|
response=$(kubectl cordon --selector invalid=label)
|
||||||
kube::test::if_has_not_string "${response}" 'cordoned'
|
kube::test::if_has_not_string "${response}" 'cordoned'
|
||||||
|
@ -19,6 +19,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
@ -29,6 +30,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/json"
|
"k8s.io/apimachinery/pkg/util/json"
|
||||||
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
@ -40,6 +42,9 @@ import (
|
|||||||
|
|
||||||
// AnnotateOptions have the data required to perform the annotate operation
|
// AnnotateOptions have the data required to perform the annotate operation
|
||||||
type AnnotateOptions struct {
|
type AnnotateOptions struct {
|
||||||
|
PrintFlags *printers.PrintFlags
|
||||||
|
PrintObj printers.ResourcePrinterFunc
|
||||||
|
|
||||||
// Filename options
|
// Filename options
|
||||||
resource.FilenameOptions
|
resource.FilenameOptions
|
||||||
RecordFlags *genericclioptions.RecordFlags
|
RecordFlags *genericclioptions.RecordFlags
|
||||||
@ -99,8 +104,9 @@ var (
|
|||||||
|
|
||||||
func NewAnnotateOptions(ioStreams genericclioptions.IOStreams) *AnnotateOptions {
|
func NewAnnotateOptions(ioStreams genericclioptions.IOStreams) *AnnotateOptions {
|
||||||
return &AnnotateOptions{
|
return &AnnotateOptions{
|
||||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
PrintFlags: printers.NewPrintFlags("annotated"),
|
||||||
|
|
||||||
|
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||||
Recorder: genericclioptions.NoopRecorder{},
|
Recorder: genericclioptions.NoopRecorder{},
|
||||||
IOStreams: ioStreams,
|
IOStreams: ioStreams,
|
||||||
}
|
}
|
||||||
@ -131,8 +137,8 @@ func NewCmdAnnotate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *c
|
|||||||
|
|
||||||
// bind flag structs
|
// bind flag structs
|
||||||
o.RecordFlags.AddFlags(cmd)
|
o.RecordFlags.AddFlags(cmd)
|
||||||
|
o.PrintFlags.AddFlags(cmd)
|
||||||
|
|
||||||
cmdutil.AddPrinterFlags(cmd)
|
|
||||||
cmdutil.AddIncludeUninitializedFlag(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.overwrite, "overwrite", o.overwrite, "If true, allow annotations to be overwritten, otherwise reject annotation updates that overwrite existing annotations.")
|
||||||
cmd.Flags().BoolVar(&o.local, "local", o.local, "If true, annotation will NOT contact api-server but run locally.")
|
cmd.Flags().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.outputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||||
o.dryrun = cmdutil.GetDryRunFlag(cmd)
|
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
|
// retrieves resource and annotation args from args
|
||||||
// also checks args to verify that all resources are specified before annotations
|
// also checks args to verify that all resources are specified before annotations
|
||||||
resources, annotationArgs, err := cmdutil.GetResourcesAndPairs(args, "annotation")
|
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 o.PrintObj(outputObj, o.Out)
|
||||||
return cmdutil.PrintObject(cmd, outputObj, o.Out)
|
|
||||||
}
|
|
||||||
cmdutil.PrintSuccess(false, o.Out, info.Object, o.dryrun, "annotated")
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,8 +18,13 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"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"
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
@ -27,9 +32,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||||
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
"github.com/golang/glog"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -48,22 +51,46 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type AutoscaleOptions struct {
|
type AutoscaleOptions struct {
|
||||||
FilenameOptions resource.FilenameOptions
|
FilenameOptions *resource.FilenameOptions
|
||||||
RecordFlags *genericclioptions.RecordFlags
|
|
||||||
|
|
||||||
|
RecordFlags *genericclioptions.RecordFlags
|
||||||
Recorder genericclioptions.Recorder
|
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{
|
return &AutoscaleOptions{
|
||||||
FilenameOptions: resource.FilenameOptions{},
|
PrintFlags: printers.NewPrintFlags("autoscaled"),
|
||||||
|
FilenameOptions: &resource.FilenameOptions{},
|
||||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||||
Recorder: genericclioptions.NoopRecorder{},
|
Recorder: genericclioptions.NoopRecorder{},
|
||||||
|
|
||||||
|
IOStreams: ioStreams,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCmdAutoscale(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
func NewCmdAutoscale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||||
o := NewAutoscaleOptions()
|
o := NewAutoscaleOptions(ioStreams)
|
||||||
|
|
||||||
validArgs := []string{"deployment", "replicaset", "replicationcontroller"}
|
validArgs := []string{"deployment", "replicaset", "replicationcontroller"}
|
||||||
argAliases := kubectl.ResourceAliases(validArgs)
|
argAliases := kubectl.ResourceAliases(validArgs)
|
||||||
@ -75,8 +102,9 @@ func NewCmdAutoscale(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
Long: autoscaleLong,
|
Long: autoscaleLong,
|
||||||
Example: autoscaleExample,
|
Example: autoscaleExample,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||||
cmdutil.CheckErr(o.RunAutoscale(f, out, cmd, args))
|
cmdutil.CheckErr(o.Validate(cmd))
|
||||||
|
cmdutil.CheckErr(o.Run())
|
||||||
},
|
},
|
||||||
ValidArgs: validArgs,
|
ValidArgs: validArgs,
|
||||||
ArgAliases: argAliases,
|
ArgAliases: argAliases,
|
||||||
@ -84,8 +112,8 @@ func NewCmdAutoscale(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
|
|
||||||
// bind flag structs
|
// bind flag structs
|
||||||
o.RecordFlags.AddFlags(cmd)
|
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().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("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.")
|
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."))
|
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)
|
cmdutil.AddDryRunFlag(cmd)
|
||||||
usage := "identifying the resource to autoscale."
|
usage := "identifying the resource to autoscale."
|
||||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, usage)
|
||||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||||
var err error
|
o.DryRun = cmdutil.GetFlagBool(cmd, "dry-run")
|
||||||
|
o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
|
||||||
|
o.Builder = f.NewBuilder()
|
||||||
|
o.CanBeAutoscaled = f.CanBeAutoscaled
|
||||||
|
o.Mapper, o.Typer = f.Object()
|
||||||
|
o.ClientForMapping = f.ClientForMapping
|
||||||
|
o.BuilderArgs = args
|
||||||
o.RecordFlags.Complete(f.Command(cmd, false))
|
o.RecordFlags.Complete(f.Command(cmd, false))
|
||||||
|
|
||||||
|
var err error
|
||||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *AutoscaleOptions) RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
func (o *AutoscaleOptions) Run() error {
|
||||||
namespace, enforceNamespace, err := f.DefaultNamespace()
|
r := o.Builder.
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate flags
|
|
||||||
if err := validateFlags(cmd); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
r := f.NewBuilder().
|
|
||||||
Internal().
|
Internal().
|
||||||
ContinueOnError().
|
ContinueOnError().
|
||||||
NamespaceParam(namespace).DefaultNamespace().
|
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
FilenameParam(o.EnforceNamespace, o.FilenameOptions).
|
||||||
ResourceTypeOrNameArgs(false, args...).
|
ResourceTypeOrNameArgs(false, o.BuilderArgs...).
|
||||||
Flatten().
|
Flatten().
|
||||||
Do()
|
Do()
|
||||||
err = r.Err()
|
if err := r.Err(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
count := 0
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mapping := info.ResourceMapping()
|
mapping := info.ResourceMapping()
|
||||||
if err := f.CanBeAutoscaled(mapping.GroupVersionKind.GroupKind()); err != nil {
|
if err := o.CanBeAutoscaled(mapping.GroupVersionKind.GroupKind()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the generator
|
generator, err := o.GeneratorFunc(info.Name, mapping)
|
||||||
var generator kubectl.StructuredGenerator
|
if err != nil {
|
||||||
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
|
return err
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate new object
|
// Generate new object
|
||||||
@ -169,11 +229,10 @@ func (o *AutoscaleOptions) RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *c
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper, typer := f.Object()
|
|
||||||
resourceMapper := &resource.Mapper{
|
resourceMapper := &resource.Mapper{
|
||||||
ObjectTyper: typer,
|
ObjectTyper: o.Typer,
|
||||||
RESTMapper: mapper,
|
RESTMapper: o.Mapper,
|
||||||
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
|
ClientMapper: resource.ClientMapperFunc(o.ClientForMapping),
|
||||||
Decoder: cmdutil.InternalVersionDecoder(),
|
Decoder: cmdutil.InternalVersionDecoder(),
|
||||||
}
|
}
|
||||||
hpa, err := resourceMapper.InfoForObject(object, nil)
|
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 {
|
if err := o.Recorder.Record(hpa.Object); err != nil {
|
||||||
glog.V(4).Infof("error recording current command: %v", err)
|
glog.V(4).Infof("error recording current command: %v", err)
|
||||||
}
|
}
|
||||||
if cmdutil.GetDryRunFlag(cmd) {
|
object = hpa.Object
|
||||||
return cmdutil.PrintObject(cmd, object, out)
|
|
||||||
|
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
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
count++
|
count++
|
||||||
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
|
printer, err := o.ToPrinter("autoscaled")
|
||||||
return cmdutil.PrintObject(cmd, object, out)
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
return printer.PrintObj(info.AsVersioned(), o.Out)
|
||||||
cmdutil.PrintSuccess(false, out, info.Object, cmdutil.GetDryRunFlag(cmd), "autoscaled")
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -21,16 +21,20 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/apis/certificates"
|
"k8s.io/kubernetes/pkg/apis/certificates"
|
||||||
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
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/resource"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||||
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"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{
|
cmd := &cobra.Command{
|
||||||
Use: "certificate SUBCOMMAND",
|
Use: "certificate SUBCOMMAND",
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
@ -41,33 +45,61 @@ func NewCmdCertificate(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(NewCmdCertificateApprove(f, out))
|
cmd.AddCommand(NewCmdCertificateApprove(f, ioStreams))
|
||||||
cmd.AddCommand(NewCmdCertificateDeny(f, out))
|
cmd.AddCommand(NewCmdCertificateDeny(f, ioStreams))
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
type CertificateOptions struct {
|
type CertificateOptions struct {
|
||||||
resource.FilenameOptions
|
resource.FilenameOptions
|
||||||
|
|
||||||
|
PrintFlags *printers.PrintFlags
|
||||||
|
PrintObj printers.ResourcePrinterFunc
|
||||||
|
|
||||||
csrNames []string
|
csrNames []string
|
||||||
outputStyle string
|
outputStyle string
|
||||||
|
|
||||||
|
clientSet internalclientset.Interface
|
||||||
|
builder *resource.Builder
|
||||||
|
|
||||||
|
genericclioptions.IOStreams
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *CertificateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||||
|
o.csrNames = args
|
||||||
|
o.outputStyle = cmdutil.GetFlagString(cmd, "output")
|
||||||
|
|
||||||
|
printer, err := o.PrintFlags.ToPrinter()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
o.PrintObj = func(obj runtime.Object, out io.Writer) error {
|
||||||
|
return printer.PrintObj(obj, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
o.builder = f.NewBuilder()
|
||||||
|
o.clientSet, err = f.ClientSet()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (options *CertificateOptions) Complete(cmd *cobra.Command, args []string) error {
|
|
||||||
options.csrNames = args
|
|
||||||
options.outputStyle = cmdutil.GetFlagString(cmd, "output")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (options *CertificateOptions) Validate() error {
|
func (o *CertificateOptions) Validate() error {
|
||||||
if len(options.csrNames) < 1 && cmdutil.IsFilenameSliceEmpty(options.Filenames) {
|
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 fmt.Errorf("one or more CSRs must be specified as <name> or -f <filename>")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCmdCertificateApprove(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
func NewCmdCertificateApprove(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||||
options := CertificateOptions{}
|
options := CertificateOptions{
|
||||||
|
PrintFlags: printers.NewPrintFlags("approved"),
|
||||||
|
IOStreams: ioStreams,
|
||||||
|
}
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "approve (-f FILENAME | NAME)",
|
Use: "approve (-f FILENAME | NAME)",
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
@ -85,9 +117,9 @@ func NewCmdCertificateApprove(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
signed certificate can do.
|
signed certificate can do.
|
||||||
`),
|
`),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
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.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.")
|
cmd.Flags().Bool("force", false, "Update the CSR even if it is already approved.")
|
||||||
@ -97,8 +129,8 @@ func NewCmdCertificateApprove(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (options *CertificateOptions) RunCertificateApprove(f cmdutil.Factory, out io.Writer, force bool) error {
|
func (o *CertificateOptions) RunCertificateApprove(force bool) error {
|
||||||
return options.modifyCertificateCondition(f, out, force, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool, string) {
|
return o.modifyCertificateCondition(o.builder, o.clientSet, force, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool) {
|
||||||
var alreadyApproved bool
|
var alreadyApproved bool
|
||||||
for _, c := range csr.Status.Conditions {
|
for _, c := range csr.Status.Conditions {
|
||||||
if c.Type == certificates.CertificateApproved {
|
if c.Type == certificates.CertificateApproved {
|
||||||
@ -106,7 +138,7 @@ func (options *CertificateOptions) RunCertificateApprove(f cmdutil.Factory, out
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if alreadyApproved {
|
if alreadyApproved {
|
||||||
return csr, true, "approved"
|
return csr, true
|
||||||
}
|
}
|
||||||
csr.Status.Conditions = append(csr.Status.Conditions, certificates.CertificateSigningRequestCondition{
|
csr.Status.Conditions = append(csr.Status.Conditions, certificates.CertificateSigningRequestCondition{
|
||||||
Type: certificates.CertificateApproved,
|
Type: certificates.CertificateApproved,
|
||||||
@ -114,12 +146,15 @@ func (options *CertificateOptions) RunCertificateApprove(f cmdutil.Factory, out
|
|||||||
Message: "This CSR was approved by kubectl certificate approve.",
|
Message: "This CSR was approved by kubectl certificate approve.",
|
||||||
LastUpdateTime: metav1.Now(),
|
LastUpdateTime: metav1.Now(),
|
||||||
})
|
})
|
||||||
return csr, false, "approved"
|
return csr, false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCmdCertificateDeny(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
func NewCmdCertificateDeny(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||||
options := CertificateOptions{}
|
options := CertificateOptions{
|
||||||
|
PrintFlags: printers.NewPrintFlags("denied"),
|
||||||
|
IOStreams: ioStreams,
|
||||||
|
}
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "deny (-f FILENAME | NAME)",
|
Use: "deny (-f FILENAME | NAME)",
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
@ -132,9 +167,9 @@ func NewCmdCertificateDeny(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
not to issue a certificate to the requestor.
|
not to issue a certificate to the requestor.
|
||||||
`),
|
`),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
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.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.")
|
cmd.Flags().Bool("force", false, "Update the CSR even if it is already denied.")
|
||||||
@ -144,8 +179,8 @@ func NewCmdCertificateDeny(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (options *CertificateOptions) RunCertificateDeny(f cmdutil.Factory, out io.Writer, force bool) error {
|
func (o *CertificateOptions) RunCertificateDeny(force bool) error {
|
||||||
return options.modifyCertificateCondition(f, out, force, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool, string) {
|
return o.modifyCertificateCondition(o.builder, o.clientSet, force, func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool) {
|
||||||
var alreadyDenied bool
|
var alreadyDenied bool
|
||||||
for _, c := range csr.Status.Conditions {
|
for _, c := range csr.Status.Conditions {
|
||||||
if c.Type == certificates.CertificateDenied {
|
if c.Type == certificates.CertificateDenied {
|
||||||
@ -153,7 +188,7 @@ func (options *CertificateOptions) RunCertificateDeny(f cmdutil.Factory, out io.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if alreadyDenied {
|
if alreadyDenied {
|
||||||
return csr, true, "denied"
|
return csr, true
|
||||||
}
|
}
|
||||||
csr.Status.Conditions = append(csr.Status.Conditions, certificates.CertificateSigningRequestCondition{
|
csr.Status.Conditions = append(csr.Status.Conditions, certificates.CertificateSigningRequestCondition{
|
||||||
Type: certificates.CertificateDenied,
|
Type: certificates.CertificateDenied,
|
||||||
@ -161,17 +196,13 @@ func (options *CertificateOptions) RunCertificateDeny(f cmdutil.Factory, out io.
|
|||||||
Message: "This CSR was approved by kubectl certificate deny.",
|
Message: "This CSR was approved by kubectl certificate deny.",
|
||||||
LastUpdateTime: metav1.Now(),
|
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(builder *resource.Builder, clientSet internalclientset.Interface, force bool, modify func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool)) error {
|
||||||
var found int
|
var found int
|
||||||
c, err := f.ClientSet()
|
r := builder.
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
r := f.NewBuilder().
|
|
||||||
Internal().
|
Internal().
|
||||||
ContinueOnError().
|
ContinueOnError().
|
||||||
FilenameParam(false, &options.FilenameOptions).
|
FilenameParam(false, &options.FilenameOptions).
|
||||||
@ -180,14 +211,14 @@ func (options *CertificateOptions) modifyCertificateCondition(f cmdutil.Factory,
|
|||||||
Flatten().
|
Flatten().
|
||||||
Latest().
|
Latest().
|
||||||
Do()
|
Do()
|
||||||
err = r.Visit(func(info *resource.Info, err error) error {
|
err := r.Visit(func(info *resource.Info, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
csr := info.Object.(*certificates.CertificateSigningRequest)
|
csr := info.Object.(*certificates.CertificateSigningRequest)
|
||||||
csr, hasCondition, verb := modify(csr)
|
csr, hasCondition := modify(csr)
|
||||||
if !hasCondition || force {
|
if !hasCondition || force {
|
||||||
csr, err = c.Certificates().
|
csr, err = clientSet.Certificates().
|
||||||
CertificateSigningRequests().
|
CertificateSigningRequests().
|
||||||
UpdateApproval(csr)
|
UpdateApproval(csr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -195,11 +226,11 @@ func (options *CertificateOptions) modifyCertificateCondition(f cmdutil.Factory,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
found++
|
found++
|
||||||
cmdutil.PrintSuccess(options.outputStyle == "name", out, info.Object, false, verb)
|
|
||||||
return nil
|
return options.PrintObj(info.AsVersioned(), options.Out)
|
||||||
})
|
})
|
||||||
if found == 0 {
|
if found == 0 {
|
||||||
fmt.Fprintf(out, "No resources found\n")
|
fmt.Fprintf(options.Out, "No resources found\n")
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,11 @@ import (
|
|||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||||
|
restclient "k8s.io/client-go/rest"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
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/resource"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||||
|
|
||||||
@ -43,41 +45,62 @@ var (
|
|||||||
kubectl cluster-info`))
|
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{
|
cmd := &cobra.Command{
|
||||||
Use: "cluster-info",
|
Use: "cluster-info",
|
||||||
Short: i18n.T("Display cluster info"),
|
Short: i18n.T("Display cluster info"),
|
||||||
Long: longDescr,
|
Long: longDescr,
|
||||||
Example: clusterinfoExample,
|
Example: clusterinfoExample,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
err := RunClusterInfo(f, out, cmd)
|
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||||
cmdutil.CheckErr(err)
|
cmdutil.CheckErr(o.Run())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.AddCommand(NewCmdClusterInfoDump(f, out))
|
cmd.AddCommand(NewCmdClusterInfoDump(f, ioStreams))
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunClusterInfo(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) error {
|
func (o *ClusterInfoOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||||
client, err := f.ClientConfig()
|
var err error
|
||||||
|
o.Client, err = f.ClientConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
printService(out, "Kubernetes master", client.Host)
|
|
||||||
|
|
||||||
cmdNamespace := cmdutil.GetFlagString(cmd, "namespace")
|
cmdNamespace := cmdutil.GetFlagString(cmd, "namespace")
|
||||||
if cmdNamespace == "" {
|
if cmdNamespace == "" {
|
||||||
cmdNamespace = metav1.NamespaceSystem
|
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)
|
// TODO use generalized labels once they are implemented (#341)
|
||||||
b := f.NewBuilder().
|
b := o.Builder.
|
||||||
Internal().
|
Internal().
|
||||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||||
LabelSelectorParam("kubernetes.io/cluster-service=true").
|
LabelSelectorParam("kubernetes.io/cluster-service=true").
|
||||||
ResourceTypeOrNameArgs(false, []string{"services"}...).
|
ResourceTypeOrNameArgs(false, []string{"services"}...).
|
||||||
Latest()
|
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 {
|
if err != nil {
|
||||||
return err
|
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)
|
name = utilnet.JoinSchemeNamePort(scheme, service.ObjectMeta.Name, port.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(client.GroupVersion.Group) == 0 {
|
if len(o.Client.GroupVersion.Group) == 0 {
|
||||||
link = client.Host + "/api/" + client.GroupVersion.Version + "/namespaces/" + service.ObjectMeta.Namespace + "/services/" + name + "/proxy"
|
link = o.Client.Host + "/api/" + o.Client.GroupVersion.Version + "/namespaces/" + service.ObjectMeta.Namespace + "/services/" + name + "/proxy"
|
||||||
} else {
|
} 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 {
|
if len(name) == 0 {
|
||||||
name = service.ObjectMeta.Name
|
name = service.ObjectMeta.Name
|
||||||
}
|
}
|
||||||
printService(out, name, link)
|
printService(o.Out, name, link)
|
||||||
}
|
}
|
||||||
return nil
|
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
|
return err
|
||||||
|
|
||||||
// TODO consider printing more information about cluster
|
// TODO consider printing more information about cluster
|
||||||
|
@ -28,19 +28,34 @@ import (
|
|||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||||
"k8s.io/kubernetes/pkg/printers"
|
"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
|
// 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{
|
cmd := &cobra.Command{
|
||||||
Use: "dump",
|
Use: "dump",
|
||||||
Short: i18n.T("Dump lots of relevant info for debugging and diagnosis"),
|
Short: i18n.T("Dump lots of relevant info for debugging and diagnosis"),
|
||||||
Long: dumpLong,
|
Long: dumpLong,
|
||||||
Example: dumpExample,
|
Example: dumpExample,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
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"))
|
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
|
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)
|
timeout, err := cmdutil.GetPodRunningTimeoutFlag(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cmdutil.UsageErrorf(cmd, err.Error())
|
return cmdutil.UsageErrorf(cmd, err.Error())
|
||||||
@ -99,14 +127,12 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
printer := &printers.JSONPrinter{}
|
|
||||||
|
|
||||||
nodes, err := clientset.Core().Nodes().List(metav1.ListOptions{})
|
nodes, err := clientset.Core().Nodes().List(metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +165,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +173,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +181,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +189,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +197,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +205,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +214,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||||||
return err
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +241,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||||||
for ix := range pods.Items {
|
for ix := range pods.Items {
|
||||||
pod := &pods.Items[ix]
|
pod := &pods.Items[ix]
|
||||||
containers := pod.Spec.Containers
|
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 {
|
for i := range containers {
|
||||||
printContainer(writer, containers[i], pod)
|
printContainer(writer, containers[i], pod)
|
||||||
@ -227,7 +253,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, out io.Writer) error
|
|||||||
dir = "standard output"
|
dir = "standard output"
|
||||||
}
|
}
|
||||||
if dir != "-" {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -17,27 +17,27 @@ limitations under the License.
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSetupOutputWriterNoOp(t *testing.T) {
|
func TestSetupOutputWriterNoOp(t *testing.T) {
|
||||||
tests := []string{"", "-"}
|
tests := []string{"", "-"}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
out := &bytes.Buffer{}
|
_, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||||
f := cmdtesting.NewTestFactory()
|
f := cmdtesting.NewTestFactory()
|
||||||
defer f.Cleanup()
|
defer f.Cleanup()
|
||||||
|
|
||||||
cmd := NewCmdClusterInfoDump(f, os.Stdout)
|
cmd := NewCmdClusterInfoDump(f, genericclioptions.NewTestIOStreamsDiscard())
|
||||||
cmd.Flag("output-directory").Value.Set(test)
|
cmd.Flag("output-directory").Value.Set(test)
|
||||||
writer := setupOutputWriter(cmd, out, "/some/file/that/should/be/ignored")
|
writer := setupOutputWriter(cmd, buf, "/some/file/that/should/be/ignored")
|
||||||
if writer != out {
|
if writer != buf {
|
||||||
t.Errorf("expected: %v, saw: %v", out, writer)
|
t.Errorf("expected: %v, saw: %v", buf, writer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,15 +51,15 @@ func TestSetupOutputWriterFile(t *testing.T) {
|
|||||||
fullPath := path.Join(dir, file)
|
fullPath := path.Join(dir, file)
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
out := &bytes.Buffer{}
|
_, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||||
f := cmdtesting.NewTestFactory()
|
f := cmdtesting.NewTestFactory()
|
||||||
defer f.Cleanup()
|
defer f.Cleanup()
|
||||||
|
|
||||||
cmd := NewCmdClusterInfoDump(f, os.Stdout)
|
cmd := NewCmdClusterInfoDump(f, genericclioptions.NewTestIOStreamsDiscard())
|
||||||
cmd.Flag("output-directory").Value.Set(dir)
|
cmd.Flag("output-directory").Value.Set(dir)
|
||||||
writer := setupOutputWriter(cmd, out, file)
|
writer := setupOutputWriter(cmd, buf, file)
|
||||||
if writer == out {
|
if writer == buf {
|
||||||
t.Errorf("expected: %v, saw: %v", out, writer)
|
t.Errorf("expected: %v, saw: %v", buf, writer)
|
||||||
}
|
}
|
||||||
output := "some data here"
|
output := "some data here"
|
||||||
writer.Write([]byte(output))
|
writer.Write([]byte(output))
|
||||||
|
@ -276,18 +276,18 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
|
|||||||
rollout.NewCmdRollout(f, out, err),
|
rollout.NewCmdRollout(f, out, err),
|
||||||
NewCmdRollingUpdate(f, out),
|
NewCmdRollingUpdate(f, out),
|
||||||
NewCmdScale(f, out, err),
|
NewCmdScale(f, out, err),
|
||||||
NewCmdAutoscale(f, out),
|
NewCmdAutoscale(f, ioStreams),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Message: "Cluster Management Commands:",
|
Message: "Cluster Management Commands:",
|
||||||
Commands: []*cobra.Command{
|
Commands: []*cobra.Command{
|
||||||
NewCmdCertificate(f, out),
|
NewCmdCertificate(f, ioStreams),
|
||||||
NewCmdClusterInfo(f, out),
|
NewCmdClusterInfo(f, ioStreams),
|
||||||
NewCmdTop(f, out, err),
|
NewCmdTop(f, out, err),
|
||||||
NewCmdCordon(f, out),
|
NewCmdCordon(f, ioStreams),
|
||||||
NewCmdUncordon(f, out),
|
NewCmdUncordon(f, ioStreams),
|
||||||
NewCmdDrain(f, out, err),
|
NewCmdDrain(f, ioStreams),
|
||||||
NewCmdTaint(f, out),
|
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),
|
NewCmdExec(f, in, out, err),
|
||||||
NewCmdPortForward(f, out, err),
|
NewCmdPortForward(f, out, err),
|
||||||
NewCmdProxy(f, out),
|
NewCmdProxy(f, out),
|
||||||
NewCmdCp(f, out, err),
|
NewCmdCp(f, ioStreams),
|
||||||
auth.NewCmdAuth(f, out, err),
|
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),
|
NewCmdApply("kubectl", f, ioStreams),
|
||||||
NewCmdPatch(f, out),
|
NewCmdPatch(f, out),
|
||||||
NewCmdReplace(f, out, err),
|
NewCmdReplace(f, out, err),
|
||||||
NewCmdConvert(f, out),
|
NewCmdConvert(f, ioStreams),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Message: "Settings Commands:",
|
Message: "Settings Commands:",
|
||||||
Commands: []*cobra.Command{
|
Commands: []*cobra.Command{
|
||||||
NewCmdLabel(f, out, err),
|
NewCmdLabel(f, ioStreams),
|
||||||
NewCmdAnnotate(f, ioStreams),
|
NewCmdAnnotate(f, ioStreams),
|
||||||
NewCmdCompletion(out, ""),
|
NewCmdCompletion(out, ""),
|
||||||
},
|
},
|
||||||
|
@ -18,7 +18,6 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
@ -27,6 +26,7 @@ import (
|
|||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
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/resource"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||||
"k8s.io/kubernetes/pkg/printers"
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
@ -61,8 +61,8 @@ var (
|
|||||||
|
|
||||||
// NewCmdConvert creates a command object for the generic "convert" action, which
|
// NewCmdConvert creates a command object for the generic "convert" action, which
|
||||||
// translates the config file into a given version.
|
// translates the config file into a given version.
|
||||||
func NewCmdConvert(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
func NewCmdConvert(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||||
options := NewConvertOptions()
|
options := NewConvertOptions(ioStreams)
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "convert -f FILENAME",
|
Use: "convert -f FILENAME",
|
||||||
@ -71,18 +71,17 @@ func NewCmdConvert(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
Long: convert_long,
|
Long: convert_long,
|
||||||
Example: convert_example,
|
Example: convert_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
err := options.Complete(f, out, cmd)
|
cmdutil.CheckErr(options.Complete(f, cmd))
|
||||||
cmdutil.CheckErr(err)
|
cmdutil.CheckErr(options.RunConvert())
|
||||||
err = options.RunConvert()
|
|
||||||
cmdutil.CheckErr(err)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options.PrintFlags.AddFlags(cmd)
|
||||||
|
|
||||||
usage := "to need to get converted."
|
usage := "to need to get converted."
|
||||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||||
cmd.MarkFlagRequired("filename")
|
cmd.MarkFlagRequired("filename")
|
||||||
cmdutil.AddValidateFlags(cmd)
|
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().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').)"))
|
cmd.Flags().String("output-version", "", i18n.T("Output the formatted object with the given group version (for ex: 'extensions/v1beta1').)"))
|
||||||
return cmd
|
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
|
// ConvertOptions have the data required to perform the convert operation
|
||||||
type ConvertOptions struct {
|
type ConvertOptions struct {
|
||||||
|
PrintFlags *printers.PrintFlags
|
||||||
|
PrintObj printers.ResourcePrinterFunc
|
||||||
|
|
||||||
resource.FilenameOptions
|
resource.FilenameOptions
|
||||||
|
|
||||||
builder *resource.Builder
|
builder *resource.Builder
|
||||||
local bool
|
local bool
|
||||||
|
|
||||||
out io.Writer
|
genericclioptions.IOStreams
|
||||||
printer printers.ResourcePrinter
|
|
||||||
|
|
||||||
specifiedOutputVersion schema.GroupVersion
|
specifiedOutputVersion schema.GroupVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConvertOptions() *ConvertOptions {
|
func NewConvertOptions(ioStreams genericclioptions.IOStreams) *ConvertOptions {
|
||||||
return &ConvertOptions{local: true}
|
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)
|
// 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.
|
// 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)
|
o.specifiedOutputVersion, err = outputVersion(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -145,21 +149,13 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C
|
|||||||
Flatten()
|
Flatten()
|
||||||
|
|
||||||
// build the printer
|
// build the printer
|
||||||
o.out = out
|
printer, err := o.PrintFlags.ToPrinter()
|
||||||
outputFormat := cmdutil.GetFlagString(cmd, "output")
|
if err != nil {
|
||||||
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)
|
|
||||||
}
|
|
||||||
o.printer, err = cmdutil.PrinterForOptions(cmdutil.ExtractCmdPrintOptions(cmd, false))
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
o.PrintObj = printer.PrintObj
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// RunConvert implements the generic Convert command
|
// RunConvert implements the generic Convert command
|
||||||
func (o *ConvertOptions) RunConvert() error {
|
func (o *ConvertOptions) RunConvert() error {
|
||||||
@ -189,10 +185,10 @@ func (o *ConvertOptions) RunConvert() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// objectListToVersionedObject receives a list of api objects and a group version
|
||||||
|
@ -20,10 +20,12 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/client-go/rest/fake"
|
"k8s.io/client-go/rest/fake"
|
||||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
)
|
)
|
||||||
|
|
||||||
type testcase struct {
|
type testcase struct {
|
||||||
@ -34,7 +36,6 @@ type testcase struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type checkField struct {
|
type checkField struct {
|
||||||
template string
|
|
||||||
expected string
|
expected string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,8 +47,7 @@ func TestConvertObject(t *testing.T) {
|
|||||||
outputVersion: "extensions/v1beta1",
|
outputVersion: "extensions/v1beta1",
|
||||||
fields: []checkField{
|
fields: []checkField{
|
||||||
{
|
{
|
||||||
template: "{{.apiVersion}}",
|
expected: "apiVersion: extensions/v1beta1",
|
||||||
expected: "extensions/v1beta1",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -57,8 +57,7 @@ func TestConvertObject(t *testing.T) {
|
|||||||
outputVersion: "apps/v1beta2",
|
outputVersion: "apps/v1beta2",
|
||||||
fields: []checkField{
|
fields: []checkField{
|
||||||
{
|
{
|
||||||
template: "{{.apiVersion}}",
|
expected: "apiVersion: apps/v1beta2",
|
||||||
expected: "apps/v1beta2",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -68,16 +67,13 @@ func TestConvertObject(t *testing.T) {
|
|||||||
outputVersion: "autoscaling/v2beta1",
|
outputVersion: "autoscaling/v2beta1",
|
||||||
fields: []checkField{
|
fields: []checkField{
|
||||||
{
|
{
|
||||||
template: "{{.apiVersion}}",
|
expected: "apiVersion: autoscaling/v2beta1",
|
||||||
expected: "autoscaling/v2beta1",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
template: "{{(index .spec.metrics 0).resource.name}}",
|
expected: "name: cpu",
|
||||||
expected: "cpu",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
template: "{{(index .spec.metrics 0).resource.targetAverageUtilization}}",
|
expected: "targetAverageUtilization: 50",
|
||||||
expected: "50",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -87,12 +83,10 @@ func TestConvertObject(t *testing.T) {
|
|||||||
outputVersion: "autoscaling/v1",
|
outputVersion: "autoscaling/v1",
|
||||||
fields: []checkField{
|
fields: []checkField{
|
||||||
{
|
{
|
||||||
template: "{{.apiVersion}}",
|
expected: "apiVersion: autoscaling/v1",
|
||||||
expected: "autoscaling/v1",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
template: "{{.spec.targetCPUUtilizationPercentage}}",
|
expected: "targetCPUUtilizationPercentage: 50",
|
||||||
expected: "50",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -113,13 +107,13 @@ func TestConvertObject(t *testing.T) {
|
|||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
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("filename", tc.file)
|
||||||
cmd.Flags().Set("output-version", tc.outputVersion)
|
cmd.Flags().Set("output-version", tc.outputVersion)
|
||||||
cmd.Flags().Set("local", "true")
|
cmd.Flags().Set("local", "true")
|
||||||
cmd.Flags().Set("output", "go-template="+field.template)
|
cmd.Flags().Set("output", "yaml")
|
||||||
cmd.Run(cmd, []string{})
|
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())
|
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"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||||
|
|
||||||
"github.com/renstrom/dedent"
|
"github.com/renstrom/dedent"
|
||||||
@ -61,8 +64,26 @@ var (
|
|||||||
/file/path for a local file`)
|
/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.
|
// 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{
|
cmd := &cobra.Command{
|
||||||
Use: "cp <file-spec-src> <file-spec-dest>",
|
Use: "cp <file-spec-src> <file-spec-dest>",
|
||||||
DisableFlagsInUseLine: true,
|
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.",
|
Long: "Copy files and directories to and from containers.",
|
||||||
Example: cpExample,
|
Example: cpExample,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmdutil.CheckErr(runCopy(f, cmd, cmdOut, cmdErr, args))
|
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||||
|
cmdutil.CheckErr(o.Run(args))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().StringP("container", "c", "", "Container name. If omitted, the first container in the pod will be chosen")
|
cmd.Flags().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
|
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 {
|
if len(args) != 2 {
|
||||||
return cmdutil.UsageErrorf(cmd, cpUsageStr)
|
return cmdutil.UsageErrorf(cmd, cpUsageStr)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *CopyOptions) Run(args []string) error {
|
||||||
srcSpec, err := extractFileSpec(args[0])
|
srcSpec, err := extractFileSpec(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -132,19 +179,19 @@ func runCopy(f cmdutil.Factory, cmd *cobra.Command, out, cmderr io.Writer, args
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(srcSpec.PodName) != 0 {
|
if len(srcSpec.PodName) != 0 {
|
||||||
return copyFromPod(f, cmd, cmderr, srcSpec, destSpec)
|
return o.copyFromPod(srcSpec, destSpec)
|
||||||
}
|
}
|
||||||
if len(destSpec.PodName) != 0 {
|
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
|
// checkDestinationIsDir receives a destination fileSpec and
|
||||||
// determines if the provided destination path exists on the
|
// determines if the provided destination path exists on the
|
||||||
// pod. If the destination path does not exist or is _not_ a
|
// pod. If the destination path does not exist or is _not_ a
|
||||||
// directory, an error is returned with the exit code received.
|
// 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{
|
options := &ExecOptions{
|
||||||
StreamOptions: StreamOptions{
|
StreamOptions: StreamOptions{
|
||||||
Out: bytes.NewBuffer([]byte{}),
|
Out: bytes.NewBuffer([]byte{}),
|
||||||
@ -158,10 +205,10 @@ func checkDestinationIsDir(dest fileSpec, f cmdutil.Factory, cmd *cobra.Command)
|
|||||||
Executor: &DefaultRemoteExecutor{},
|
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 {
|
if len(src.File) == 0 || len(dest.File) == 0 {
|
||||||
return errFileCannotBeEmpty
|
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]
|
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.
|
// If no error, dest.File was found to be a directory.
|
||||||
// Copy specified src into it
|
// Copy specified src into it
|
||||||
dest.File = dest.File + "/" + path.Base(src.File)
|
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{
|
options := &ExecOptions{
|
||||||
StreamOptions: StreamOptions{
|
StreamOptions: StreamOptions{
|
||||||
In: reader,
|
In: reader,
|
||||||
Out: stdout,
|
Out: o.Out,
|
||||||
Err: stderr,
|
Err: o.ErrOut,
|
||||||
Stdin: true,
|
Stdin: true,
|
||||||
|
|
||||||
Namespace: dest.PodNamespace,
|
Namespace: dest.PodNamespace,
|
||||||
@ -205,10 +252,10 @@ func copyToPod(f cmdutil.Factory, cmd *cobra.Command, stdout, stderr io.Writer,
|
|||||||
Command: cmdArr,
|
Command: cmdArr,
|
||||||
Executor: &DefaultRemoteExecutor{},
|
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 {
|
if len(src.File) == 0 || len(dest.File) == 0 {
|
||||||
return errFileCannotBeEmpty
|
return errFileCannotBeEmpty
|
||||||
}
|
}
|
||||||
@ -218,7 +265,7 @@ func copyFromPod(f cmdutil.Factory, cmd *cobra.Command, cmderr io.Writer, src, d
|
|||||||
StreamOptions: StreamOptions{
|
StreamOptions: StreamOptions{
|
||||||
In: nil,
|
In: nil,
|
||||||
Out: outStream,
|
Out: outStream,
|
||||||
Err: cmderr,
|
Err: o.Out,
|
||||||
|
|
||||||
Namespace: src.PodNamespace,
|
Namespace: src.PodNamespace,
|
||||||
PodName: src.PodName,
|
PodName: src.PodName,
|
||||||
@ -231,7 +278,7 @@ func copyFromPod(f cmdutil.Factory, cmd *cobra.Command, cmderr io.Writer, src, d
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer outStream.Close()
|
defer outStream.Close()
|
||||||
execute(f, cmd, options)
|
o.execute(options)
|
||||||
}()
|
}()
|
||||||
prefix := getPrefix(src.File)
|
prefix := getPrefix(src.File)
|
||||||
prefix = path.Clean(prefix)
|
prefix = path.Clean(prefix)
|
||||||
@ -389,31 +436,17 @@ func getPrefix(file string) string {
|
|||||||
return strings.TrimLeft(file, "/")
|
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 {
|
if len(options.Namespace) == 0 {
|
||||||
namespace, _, err := f.DefaultNamespace()
|
options.Namespace = o.Namespace
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
options.Namespace = namespace
|
|
||||||
}
|
}
|
||||||
|
|
||||||
container := cmdutil.GetFlagString(cmd, "container")
|
if len(o.Container) > 0 {
|
||||||
if len(container) > 0 {
|
options.ContainerName = o.Container
|
||||||
options.ContainerName = container
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config, err := f.ClientConfig()
|
options.Config = o.ClientConfig
|
||||||
if err != nil {
|
options.PodClient = o.Clientset.Core()
|
||||||
return err
|
|
||||||
}
|
|
||||||
options.Config = config
|
|
||||||
|
|
||||||
clientset, err := f.ClientSet()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
options.PodClient = clientset.Core()
|
|
||||||
|
|
||||||
if err := options.Validate(); err != nil {
|
if err := options.Validate(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -36,6 +36,7 @@ import (
|
|||||||
"k8s.io/client-go/rest/fake"
|
"k8s.io/client-go/rest/fake"
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -524,9 +525,9 @@ func TestCopyToPod(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tf.ClientConfigVal = defaultClientConfig()
|
tf.ClientConfigVal = defaultClientConfig()
|
||||||
buf := bytes.NewBuffer([]byte{})
|
ioStreams, _, _, _ := genericclioptions.NewTestIOStreams()
|
||||||
errBuf := bytes.NewBuffer([]byte{})
|
|
||||||
cmd := NewCmdCp(tf, buf, errBuf)
|
cmd := NewCmdCp(tf, ioStreams)
|
||||||
|
|
||||||
srcFile, err := ioutil.TempDir("", "test")
|
srcFile, err := ioutil.TempDir("", "test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -554,6 +555,7 @@ func TestCopyToPod(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
|
opts := NewCopyOptions(ioStreams)
|
||||||
src := fileSpec{
|
src := fileSpec{
|
||||||
File: srcFile,
|
File: srcFile,
|
||||||
}
|
}
|
||||||
@ -562,8 +564,9 @@ func TestCopyToPod(t *testing.T) {
|
|||||||
PodName: "pod-name",
|
PodName: "pod-name",
|
||||||
File: test.dest,
|
File: test.dest,
|
||||||
}
|
}
|
||||||
|
opts.Complete(tf, cmd)
|
||||||
t.Run(name, func(t *testing.T) {
|
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
|
//If error is NotFound error , it indicates that the
|
||||||
//request has been sent correctly.
|
//request has been sent correctly.
|
||||||
//Treat this as no error.
|
//Treat this as no error.
|
||||||
|
@ -19,7 +19,6 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"math"
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -42,18 +41,23 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||||
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DrainOptions struct {
|
type DrainOptions struct {
|
||||||
|
PrintFlags *printers.PrintFlags
|
||||||
|
ToPrinter func(string) (printers.ResourcePrinterFunc, error)
|
||||||
|
|
||||||
|
Namespace string
|
||||||
client kubernetes.Interface
|
client kubernetes.Interface
|
||||||
restClient *restclient.RESTClient
|
restClient *restclient.RESTClient
|
||||||
Factory cmdutil.Factory
|
|
||||||
Force bool
|
Force bool
|
||||||
DryRun bool
|
DryRun bool
|
||||||
GracePeriodSeconds int
|
GracePeriodSeconds int
|
||||||
@ -65,9 +69,9 @@ type DrainOptions struct {
|
|||||||
PodSelector string
|
PodSelector string
|
||||||
mapper meta.RESTMapper
|
mapper meta.RESTMapper
|
||||||
nodeInfos []*resource.Info
|
nodeInfos []*resource.Info
|
||||||
Out io.Writer
|
|
||||||
ErrOut io.Writer
|
|
||||||
typer runtime.ObjectTyper
|
typer runtime.ObjectTyper
|
||||||
|
|
||||||
|
genericclioptions.IOStreams
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes a pod and returns a bool indicating whether or not to operate on the
|
// Takes a pod and returns a bool indicating whether or not to operate on the
|
||||||
@ -101,8 +105,12 @@ var (
|
|||||||
kubectl cordon foo`))
|
kubectl cordon foo`))
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCmdCordon(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
func NewCmdCordon(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||||
options := &DrainOptions{Factory: f, Out: out}
|
options := &DrainOptions{
|
||||||
|
PrintFlags: printers.NewPrintFlags("cordoned"),
|
||||||
|
|
||||||
|
IOStreams: ioStreams,
|
||||||
|
}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "cordon NODE",
|
Use: "cordon NODE",
|
||||||
@ -111,7 +119,7 @@ func NewCmdCordon(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
Long: cordon_long,
|
Long: cordon_long,
|
||||||
Example: cordon_example,
|
Example: cordon_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
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))
|
cmdutil.CheckErr(options.RunCordonOrUncordon(true))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -129,8 +137,11 @@ var (
|
|||||||
$ kubectl uncordon foo`))
|
$ kubectl uncordon foo`))
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCmdUncordon(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
func NewCmdUncordon(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||||
options := &DrainOptions{Factory: f, Out: out}
|
options := &DrainOptions{
|
||||||
|
PrintFlags: printers.NewPrintFlags("uncordoned"),
|
||||||
|
IOStreams: ioStreams,
|
||||||
|
}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "uncordon NODE",
|
Use: "uncordon NODE",
|
||||||
@ -139,7 +150,7 @@ func NewCmdUncordon(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
Long: uncordon_long,
|
Long: uncordon_long,
|
||||||
Example: uncordon_example,
|
Example: uncordon_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
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))
|
cmdutil.CheckErr(options.RunCordonOrUncordon(false))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -182,18 +193,18 @@ var (
|
|||||||
$ kubectl drain foo --grace-period=900`))
|
$ 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{
|
return &DrainOptions{
|
||||||
Factory: f,
|
PrintFlags: printers.NewPrintFlags("drained"),
|
||||||
Out: out,
|
|
||||||
ErrOut: errOut,
|
IOStreams: ioStreams,
|
||||||
backOff: clockwork.NewRealClock(),
|
backOff: clockwork.NewRealClock(),
|
||||||
GracePeriodSeconds: -1,
|
GracePeriodSeconds: -1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCmdDrain(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
func NewCmdDrain(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||||
options := NewDrainOptions(f, out, errOut)
|
options := NewDrainOptions(f, ioStreams)
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "drain NODE",
|
Use: "drain NODE",
|
||||||
@ -202,7 +213,7 @@ func NewCmdDrain(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
|||||||
Long: drain_long,
|
Long: drain_long,
|
||||||
Example: drain_example,
|
Example: drain_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmdutil.CheckErr(options.SetupDrain(cmd, args))
|
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||||
cmdutil.CheckErr(options.RunDrain())
|
cmdutil.CheckErr(options.RunDrain())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -218,9 +229,9 @@ func NewCmdDrain(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
|||||||
return cmd
|
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
|
// 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
|
var err error
|
||||||
|
|
||||||
if len(args) == 0 && !cmd.Flags().Changed("selector") {
|
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)
|
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||||
|
|
||||||
if o.client, err = o.Factory.KubernetesClientSet(); err != nil {
|
if o.client, err = f.KubernetesClientSet(); err != nil {
|
||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
o.nodeInfos = []*resource.Info{}
|
o.nodeInfos = []*resource.Info{}
|
||||||
|
|
||||||
cmdNamespace, _, err := o.Factory.DefaultNamespace()
|
o.Namespace, _, err = f.DefaultNamespace()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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().
|
Internal().
|
||||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||||
ResourceNames("nodes", args...).
|
ResourceNames("nodes", args...).
|
||||||
SingleResourceType().
|
SingleResourceType().
|
||||||
Flatten()
|
Flatten()
|
||||||
@ -294,6 +318,11 @@ func (o *DrainOptions) RunDrain() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printer, err := o.ToPrinter("drained")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
drainedNodes := sets.NewString()
|
drainedNodes := sets.NewString()
|
||||||
var fatal error
|
var fatal error
|
||||||
|
|
||||||
@ -304,7 +333,7 @@ func (o *DrainOptions) RunDrain() error {
|
|||||||
}
|
}
|
||||||
if err == nil || o.DryRun {
|
if err == nil || o.DryRun {
|
||||||
drainedNodes.Insert(info.Name)
|
drainedNodes.Insert(info.Name)
|
||||||
cmdutil.PrintSuccess(false, o.Out, info.Object, o.DryRun, "drained")
|
printer.PrintObj(info.Object, o.Out)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(o.ErrOut, "error: unable to drain node %q, aborting command...\n\n", info.Name)
|
fmt.Fprintf(o.ErrOut, "error: unable to drain node %q, aborting command...\n\n", info.Name)
|
||||||
remainingNodes := []string{}
|
remainingNodes := []string{}
|
||||||
@ -620,12 +649,17 @@ func (o *DrainOptions) waitForDelete(pods []corev1.Pod, interval, timeout time.D
|
|||||||
} else {
|
} else {
|
||||||
verbStr = "deleted"
|
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{}
|
pendingPods := []corev1.Pod{}
|
||||||
for i, pod := range pods {
|
for i, pod := range pods {
|
||||||
p, err := getPodFn(pod.Namespace, pod.Name)
|
p, err := getPodFn(pod.Namespace, pod.Name)
|
||||||
if apierrors.IsNotFound(err) || (p != nil && p.ObjectMeta.UID != pod.ObjectMeta.UID) {
|
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
|
continue
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@ -677,11 +711,6 @@ func SupportEviction(clientset kubernetes.Interface) (string, error) {
|
|||||||
// RunCordonOrUncordon runs either Cordon or Uncordon. The desired value for
|
// RunCordonOrUncordon runs either Cordon or Uncordon. The desired value for
|
||||||
// "Unschedulable" is passed as the first arg.
|
// "Unschedulable" is passed as the first arg.
|
||||||
func (o *DrainOptions) RunCordonOrUncordon(desired bool) error {
|
func (o *DrainOptions) RunCordonOrUncordon(desired bool) error {
|
||||||
cmdNamespace, _, err := o.Factory.DefaultNamespace()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
cordonOrUncordon := "cordon"
|
cordonOrUncordon := "cordon"
|
||||||
if !desired {
|
if !desired {
|
||||||
cordonOrUncordon = "un" + cordonOrUncordon
|
cordonOrUncordon = "un" + cordonOrUncordon
|
||||||
@ -706,7 +735,12 @@ func (o *DrainOptions) RunCordonOrUncordon(desired bool) error {
|
|||||||
}
|
}
|
||||||
unsched := node.Spec.Unschedulable
|
unsched := node.Spec.Unschedulable
|
||||||
if unsched == desired {
|
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 {
|
} else {
|
||||||
if !o.DryRun {
|
if !o.DryRun {
|
||||||
helper := resource.NewHelper(o.restClient, nodeInfo.Mapping)
|
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)
|
fmt.Printf("error: unable to %s node %q: %v", cordonOrUncordon, nodeInfo.Name, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, err = helper.Patch(cmdNamespace, nodeInfo.Name, types.StrategicMergePatchType, patchBytes)
|
_, err = helper.Patch(o.Namespace, nodeInfo.Name, types.StrategicMergePatchType, patchBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("error: unable to %s node %q: %v", cordonOrUncordon, nodeInfo.Name, err)
|
fmt.Printf("error: unable to %s node %q: %v", cordonOrUncordon, nodeInfo.Name, err)
|
||||||
continue
|
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 {
|
} 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ limitations under the License.
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -32,6 +31,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
policyv1beta1 "k8s.io/api/policy/v1beta1"
|
policyv1beta1 "k8s.io/api/policy/v1beta1"
|
||||||
@ -51,6 +51,7 @@ import (
|
|||||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||||
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -84,7 +85,7 @@ func TestCordon(t *testing.T) {
|
|||||||
description string
|
description string
|
||||||
node *corev1.Node
|
node *corev1.Node
|
||||||
expected *corev1.Node
|
expected *corev1.Node
|
||||||
cmd func(cmdutil.Factory, io.Writer) *cobra.Command
|
cmd func(cmdutil.Factory, genericclioptions.IOStreams) *cobra.Command
|
||||||
arg string
|
arg string
|
||||||
expectFatal bool
|
expectFatal bool
|
||||||
}{
|
}{
|
||||||
@ -196,8 +197,8 @@ func TestCordon(t *testing.T) {
|
|||||||
}
|
}
|
||||||
tf.ClientConfigVal = defaultClientConfig()
|
tf.ClientConfigVal = defaultClientConfig()
|
||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
ioStreams, _, _, _ := genericclioptions.NewTestIOStreams()
|
||||||
cmd := test.cmd(tf, buf)
|
cmd := test.cmd(tf, ioStreams)
|
||||||
|
|
||||||
saw_fatal := false
|
saw_fatal := false
|
||||||
func() {
|
func() {
|
||||||
@ -706,9 +707,8 @@ func TestDrain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
tf.ClientConfigVal = defaultClientConfig()
|
tf.ClientConfigVal = defaultClientConfig()
|
||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
ioStreams, _, _, errBuf := genericclioptions.NewTestIOStreams()
|
||||||
errBuf := bytes.NewBuffer([]byte{})
|
cmd := NewCmdDrain(tf, ioStreams)
|
||||||
cmd := NewCmdDrain(tf, buf, errBuf)
|
|
||||||
|
|
||||||
saw_fatal := false
|
saw_fatal := false
|
||||||
fatal_msg := ""
|
fatal_msg := ""
|
||||||
@ -833,9 +833,18 @@ func TestDeletePods(t *testing.T) {
|
|||||||
tf := cmdtesting.NewTestFactory()
|
tf := cmdtesting.NewTestFactory()
|
||||||
defer tf.Cleanup()
|
defer tf.Cleanup()
|
||||||
|
|
||||||
o := DrainOptions{Factory: tf}
|
o := DrainOptions{
|
||||||
|
PrintFlags: printers.NewPrintFlags("drained"),
|
||||||
|
}
|
||||||
o.mapper, _ = tf.Object()
|
o.mapper, _ = tf.Object()
|
||||||
o.Out = os.Stdout
|
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)
|
_, pods := createPods(false)
|
||||||
pendingPods, err := o.waitForDelete(pods, test.interval, test.timeout, false, test.getPodFn)
|
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
|
// bind flag structs
|
||||||
o.RecordFlags.AddFlags(cmd)
|
o.RecordFlags.AddFlags(cmd)
|
||||||
|
o.PrintFlags.AddFlags(cmd)
|
||||||
|
|
||||||
usage := "to use to edit the resource"
|
usage := "to use to edit the resource"
|
||||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||||
cmdutil.AddValidateOptionFlags(cmd, &o.ValidateOptions)
|
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().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,
|
cmd.Flags().BoolVar(&o.WindowsLineEndings, "windows-line-endings", o.WindowsLineEndings,
|
||||||
"Defaults to the line ending native to your platform.")
|
"Defaults to the line ending native to your platform.")
|
||||||
|
@ -20,10 +20,12 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/util/validation"
|
"k8s.io/apimachinery/pkg/util/validation"
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
@ -31,6 +33,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||||
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -76,17 +79,37 @@ var (
|
|||||||
type ExposeServiceOptions struct {
|
type ExposeServiceOptions struct {
|
||||||
FilenameOptions resource.FilenameOptions
|
FilenameOptions resource.FilenameOptions
|
||||||
RecordFlags *genericclioptions.RecordFlags
|
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
|
Recorder genericclioptions.Recorder
|
||||||
genericclioptions.IOStreams
|
genericclioptions.IOStreams
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewExposeServiceOptions(streams genericclioptions.IOStreams) *ExposeServiceOptions {
|
func NewExposeServiceOptions(ioStreams genericclioptions.IOStreams) *ExposeServiceOptions {
|
||||||
return &ExposeServiceOptions{
|
return &ExposeServiceOptions{
|
||||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||||
|
PrintFlags: printers.NewPrintFlags("exposed"),
|
||||||
|
|
||||||
Recorder: genericclioptions.NoopRecorder{},
|
Recorder: genericclioptions.NoopRecorder{},
|
||||||
IOStreams: streams,
|
IOStreams: ioStreams,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,15 +130,15 @@ func NewCmdExposeService(f cmdutil.Factory, streams genericclioptions.IOStreams)
|
|||||||
Example: exposeExample,
|
Example: exposeExample,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||||
cmdutil.CheckErr(o.RunExpose(f, cmd, args))
|
cmdutil.CheckErr(o.RunExpose(cmd, args))
|
||||||
},
|
},
|
||||||
ValidArgs: validArgs,
|
ValidArgs: validArgs,
|
||||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||||
}
|
}
|
||||||
|
|
||||||
o.RecordFlags.AddFlags(cmd)
|
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("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("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"))
|
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 {
|
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.RecordFlags.Complete(f.Command(cmd, false))
|
||||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
o.Namespace, o.EnforceNamespace, err = f.DefaultNamespace()
|
||||||
namespace, enforceNamespace, err := f.DefaultNamespace()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper, typer := f.Object()
|
return err
|
||||||
r := f.NewBuilder().
|
}
|
||||||
|
|
||||||
|
func (o *ExposeServiceOptions) RunExpose(cmd *cobra.Command, args []string) error {
|
||||||
|
r := o.Builder.
|
||||||
Internal().
|
Internal().
|
||||||
ContinueOnError().
|
ContinueOnError().
|
||||||
NamespaceParam(namespace).DefaultNamespace().
|
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
FilenameParam(o.EnforceNamespace, &o.FilenameOptions).
|
||||||
ResourceTypeOrNameArgs(false, args...).
|
ResourceTypeOrNameArgs(false, args...).
|
||||||
Flatten().
|
Flatten().
|
||||||
Do()
|
Do()
|
||||||
err = r.Err()
|
err := r.Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cmdutil.UsageErrorf(cmd, err.Error())
|
return cmdutil.UsageErrorf(cmd, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the generator, setup and validate all required parameters
|
// Get the generator, setup and validate all required parameters
|
||||||
generatorName := cmdutil.GetFlagString(cmd, "generator")
|
generatorName := cmdutil.GetFlagString(cmd, "generator")
|
||||||
generators := f.Generators("expose")
|
generators := o.Generators("expose")
|
||||||
generator, found := generators[generatorName]
|
generator, found := generators[generatorName]
|
||||||
if !found {
|
if !found {
|
||||||
return cmdutil.UsageErrorf(cmd, "generator %q not found.", generatorName)
|
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()
|
mapping := info.ResourceMapping()
|
||||||
if err := f.CanBeExposed(mapping.GroupVersionKind.GroupKind()); err != nil {
|
if err := o.CanBeExposed(mapping.GroupVersionKind.GroupKind()); err != nil {
|
||||||
return err
|
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
|
// For objects that need a pod selector, derive it from the exposed object in case a user
|
||||||
// didn't explicitly specify one via --selector
|
// didn't explicitly specify one via --selector
|
||||||
if s, found := params["selector"]; found && kubectl.IsZero(s) {
|
if s, found := params["selector"]; found && kubectl.IsZero(s) {
|
||||||
s, err := f.MapBasedSelectorForObject(info.Object)
|
s, err := o.MapBasedSelectorForObject(info.Object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cmdutil.UsageErrorf(cmd, "couldn't retrieve selectors via --selector flag or introspection: %v", err)
|
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
|
// For objects that need a port, derive it from the exposed object in case a user
|
||||||
// didn't explicitly specify one via --port
|
// didn't explicitly specify one via --port
|
||||||
if port, found := params["port"]; found && kubectl.IsZero(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 {
|
if err != nil {
|
||||||
return cmdutil.UsageErrorf(cmd, "couldn't find port via --port flag or introspection: %v", err)
|
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
|
// Always try to derive protocols from the exposed object, may use
|
||||||
// different protocols for different ports.
|
// different protocols for different ports.
|
||||||
if _, found := params["protocol"]; found {
|
if _, found := params["protocol"]; found {
|
||||||
protocolsMap, err := f.ProtocolsForObject(info.Object)
|
protocolsMap, err := o.ProtocolsForObject(info.Object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cmdutil.UsageErrorf(cmd, "couldn't find protocol via introspection: %v", err)
|
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"]) {
|
if kubectl.IsZero(params["labels"]) {
|
||||||
labels, err := f.LabelsForObject(info.Object)
|
labels, err := o.LabelsForObject(info.Object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -270,9 +311,9 @@ func (o *ExposeServiceOptions) RunExpose(f cmdutil.Factory, cmd *cobra.Command,
|
|||||||
}
|
}
|
||||||
|
|
||||||
resourceMapper := &resource.Mapper{
|
resourceMapper := &resource.Mapper{
|
||||||
ObjectTyper: typer,
|
ObjectTyper: o.Typer,
|
||||||
RESTMapper: mapper,
|
RESTMapper: o.Mapper,
|
||||||
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
|
ClientMapper: resource.ClientMapperFunc(o.ClientForMapping),
|
||||||
Decoder: cmdutil.InternalVersionDecoder(),
|
Decoder: cmdutil.InternalVersionDecoder(),
|
||||||
}
|
}
|
||||||
info, err = resourceMapper.InfoForObject(object, nil)
|
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)
|
glog.V(4).Infof("error recording current command: %v", err)
|
||||||
}
|
}
|
||||||
info.Refresh(object, true)
|
info.Refresh(object, true)
|
||||||
if cmdutil.GetDryRunFlag(cmd) {
|
if o.DryRun {
|
||||||
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
|
return o.PrintObj(object, o.Out)
|
||||||
return cmdutil.PrintObject(cmd, object, o.Out)
|
|
||||||
}
|
|
||||||
cmdutil.PrintSuccess(false, o.Out, info.Object, true, "exposed")
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info.Object, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info.Object, cmdutil.InternalVersionJSONEncoder()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize the object with the annotation applied.
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
|
return o.PrintObj(info.AsVersioned(), o.Out)
|
||||||
return cmdutil.PrintObject(cmd, object, o.Out)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdutil.PrintSuccess(false, o.Out, info.Object, false, "exposed")
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -79,7 +79,7 @@ func TestRunExposeService(t *testing.T) {
|
|||||||
Selector: map[string]string{"app": "go"},
|
Selector: map[string]string{"app": "go"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: "service \"foo\" exposed",
|
expected: "service/foo exposed",
|
||||||
status: 200,
|
status: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -110,7 +110,7 @@ func TestRunExposeService(t *testing.T) {
|
|||||||
Selector: map[string]string{"func": "stream"},
|
Selector: map[string]string{"func": "stream"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: "service \"foo\" exposed",
|
expected: "service/foo exposed",
|
||||||
status: 200,
|
status: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -142,7 +142,7 @@ func TestRunExposeService(t *testing.T) {
|
|||||||
Selector: map[string]string{"run": "this"},
|
Selector: map[string]string{"run": "this"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: "service \"mayor\" exposed",
|
expected: "service/mayor exposed",
|
||||||
status: 200,
|
status: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -237,7 +237,7 @@ func TestRunExposeService(t *testing.T) {
|
|||||||
ClusterIP: "10.10.10.10",
|
ClusterIP: "10.10.10.10",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: "service \"foo\" exposed",
|
expected: "service /foo exposed",
|
||||||
status: 200,
|
status: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -269,7 +269,7 @@ func TestRunExposeService(t *testing.T) {
|
|||||||
ClusterIP: api.ClusterIPNone,
|
ClusterIP: api.ClusterIPNone,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: "service \"foo\" exposed",
|
expected: "service/foo exposed",
|
||||||
status: 200,
|
status: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -295,7 +295,7 @@ func TestRunExposeService(t *testing.T) {
|
|||||||
ClusterIP: api.ClusterIPNone,
|
ClusterIP: api.ClusterIPNone,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: "service \"foo\" exposed",
|
expected: "service/foo exposed",
|
||||||
status: 200,
|
status: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -353,7 +353,7 @@ func TestRunExposeService(t *testing.T) {
|
|||||||
Selector: map[string]string{"svc": "frompod"},
|
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,
|
status: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -500,7 +500,7 @@ func TestRunExposeService(t *testing.T) {
|
|||||||
|
|
||||||
out := buf.String()
|
out := buf.String()
|
||||||
if _, ok := test.flags["dry-run"]; ok {
|
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) {
|
if !strings.Contains(out, test.expected) {
|
||||||
|
@ -18,7 +18,6 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -40,6 +39,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||||
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LabelOptions have the data required to perform the label operation
|
// LabelOptions have the data required to perform the label operation
|
||||||
@ -48,6 +48,9 @@ type LabelOptions struct {
|
|||||||
resource.FilenameOptions
|
resource.FilenameOptions
|
||||||
RecordFlags *genericclioptions.RecordFlags
|
RecordFlags *genericclioptions.RecordFlags
|
||||||
|
|
||||||
|
PrintFlags *printers.PrintFlags
|
||||||
|
ToPrinter func(string) (printers.ResourcePrinterFunc, error)
|
||||||
|
|
||||||
// Common user flags
|
// Common user flags
|
||||||
overwrite bool
|
overwrite bool
|
||||||
list bool
|
list bool
|
||||||
@ -66,8 +69,7 @@ type LabelOptions struct {
|
|||||||
Recorder genericclioptions.Recorder
|
Recorder genericclioptions.Recorder
|
||||||
|
|
||||||
// Common shared fields
|
// Common shared fields
|
||||||
out io.Writer
|
genericclioptions.IOStreams
|
||||||
errout io.Writer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -100,19 +102,19 @@ var (
|
|||||||
kubectl label pods foo bar-`))
|
kubectl label pods foo bar-`))
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewLabelOptions(out, errOut io.Writer) *LabelOptions {
|
func NewLabelOptions(ioStreams genericclioptions.IOStreams) *LabelOptions {
|
||||||
return &LabelOptions{
|
return &LabelOptions{
|
||||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||||
|
|
||||||
Recorder: genericclioptions.NoopRecorder{},
|
Recorder: genericclioptions.NoopRecorder{},
|
||||||
|
|
||||||
out: out,
|
PrintFlags: printers.NewPrintFlags("labeled"),
|
||||||
errout: errOut,
|
|
||||||
|
IOStreams: ioStreams,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCmdLabel(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
func NewCmdLabel(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||||
o := NewLabelOptions(out, errOut)
|
o := NewLabelOptions(ioStreams)
|
||||||
|
|
||||||
validArgs := cmdutil.ValidArgList(f)
|
validArgs := cmdutil.ValidArgList(f)
|
||||||
|
|
||||||
@ -136,8 +138,8 @@ func NewCmdLabel(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
o.RecordFlags.AddFlags(cmd)
|
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.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.list, "list", o.list, "If true, display the labels for a given resource.")
|
||||||
cmd.Flags().BoolVar(&o.local, "local", o.local, "If true, label will NOT contact api-server but run locally.")
|
cmd.Flags().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.outputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||||
o.dryrun = cmdutil.GetDryRunFlag(cmd)
|
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")
|
resources, labelArgs, err := cmdutil.GetResourcesAndPairs(args, "label")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -255,7 +270,7 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
|
|||||||
}
|
}
|
||||||
for _, label := range o.removeLabels {
|
for _, label := range o.removeLabels {
|
||||||
if _, ok := accessor.GetLabels()[label]; !ok {
|
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 := ""
|
indent := ""
|
||||||
if !one {
|
if !one {
|
||||||
indent = " "
|
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() {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(o.outputFormat) > 0 {
|
printer, err := o.ToPrinter(dataChangeMsg)
|
||||||
return cmdutil.PrintObject(cmd, outputObj, o.out)
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
cmdutil.PrintSuccess(false, o.out, info.Object, o.dryrun, dataChangeMsg)
|
printer.PrintObj(info.AsVersioned(), o.Out)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
"k8s.io/client-go/rest/fake"
|
"k8s.io/client-go/rest/fake"
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -327,14 +328,15 @@ func TestLabelErrors(t *testing.T) {
|
|||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfigVal = defaultClientConfig()
|
tf.ClientConfigVal = defaultClientConfig()
|
||||||
|
|
||||||
|
ioStreams, _, _, _ := genericclioptions.NewTestIOStreams()
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
cmd := NewCmdLabel(tf, buf, buf)
|
cmd := NewCmdLabel(tf, ioStreams)
|
||||||
cmd.SetOutput(buf)
|
cmd.SetOutput(buf)
|
||||||
|
|
||||||
for k, v := range testCase.flags {
|
for k, v := range testCase.flags {
|
||||||
cmd.Flags().Set(k, v)
|
cmd.Flags().Set(k, v)
|
||||||
}
|
}
|
||||||
opts := NewLabelOptions(buf, buf)
|
opts := NewLabelOptions(ioStreams)
|
||||||
err := opts.Complete(tf, cmd, testCase.args)
|
err := opts.Complete(tf, cmd, testCase.args)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = opts.Validate()
|
err = opts.Validate()
|
||||||
@ -389,9 +391,9 @@ func TestLabelForResourceFromFile(t *testing.T) {
|
|||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfigVal = defaultClientConfig()
|
tf.ClientConfigVal = defaultClientConfig()
|
||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||||
cmd := NewCmdLabel(tf, buf, buf)
|
cmd := NewCmdLabel(tf, ioStreams)
|
||||||
opts := NewLabelOptions(buf, buf)
|
opts := NewLabelOptions(ioStreams)
|
||||||
opts.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
|
opts.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
|
||||||
err := opts.Complete(tf, cmd, []string{"a=b"})
|
err := opts.Complete(tf, cmd, []string{"a=b"})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -422,9 +424,9 @@ func TestLabelLocal(t *testing.T) {
|
|||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfigVal = defaultClientConfig()
|
tf.ClientConfigVal = defaultClientConfig()
|
||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||||
cmd := NewCmdLabel(tf, buf, buf)
|
cmd := NewCmdLabel(tf, ioStreams)
|
||||||
opts := NewLabelOptions(buf, buf)
|
opts := NewLabelOptions(ioStreams)
|
||||||
opts.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
|
opts.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
|
||||||
opts.local = true
|
opts.local = true
|
||||||
err := opts.Complete(tf, cmd, []string{"a=b"})
|
err := opts.Complete(tf, cmd, []string{"a=b"})
|
||||||
@ -480,10 +482,10 @@ func TestLabelMultipleObjects(t *testing.T) {
|
|||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfigVal = defaultClientConfig()
|
tf.ClientConfigVal = defaultClientConfig()
|
||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||||
opts := NewLabelOptions(buf, buf)
|
opts := NewLabelOptions(ioStreams)
|
||||||
opts.all = true
|
opts.all = true
|
||||||
cmd := NewCmdLabel(tf, buf, buf)
|
cmd := NewCmdLabel(tf, ioStreams)
|
||||||
err := opts.Complete(tf, cmd, []string{"pods", "a=b"})
|
err := opts.Complete(tf, cmd, []string{"pods", "a=b"})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = opts.Validate()
|
err = opts.Validate()
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
@ -40,6 +40,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
"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}
|
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 {
|
type PatchOptions struct {
|
||||||
resource.FilenameOptions
|
resource.FilenameOptions
|
||||||
RecordFlags *genericclioptions.RecordFlags
|
RecordFlags *genericclioptions.RecordFlags
|
||||||
|
PrintFlags *printers.PrintFlags
|
||||||
|
ToPrinter func(string) (printers.ResourcePrinterFunc, error)
|
||||||
|
|
||||||
Local bool
|
Local bool
|
||||||
DryRun bool
|
DryRun bool
|
||||||
@ -86,8 +89,8 @@ var (
|
|||||||
func NewPatchOptions() *PatchOptions {
|
func NewPatchOptions() *PatchOptions {
|
||||||
return &PatchOptions{
|
return &PatchOptions{
|
||||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
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.RecordFlags.AddFlags(cmd)
|
||||||
|
o.PrintFlags.AddFlags(cmd)
|
||||||
|
|
||||||
cmd.Flags().StringP("patch", "p", "", "The patch to be applied to the resource JSON file.")
|
cmd.Flags().StringP("patch", "p", "", "The patch to be applied to the resource JSON file.")
|
||||||
cmd.MarkFlagRequired("patch")
|
cmd.MarkFlagRequired("patch")
|
||||||
cmd.Flags().String("type", "strategic", fmt.Sprintf("The type of patch being provided; one of %v", sets.StringKeySet(patchTypes).List()))
|
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)
|
cmdutil.AddDryRunFlag(cmd)
|
||||||
|
|
||||||
usage := "identifying the resource to update"
|
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.OutputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||||
o.DryRun = cmdutil.GetFlagBool(cmd, "dry-run")
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,10 +238,11 @@ func (o *PatchOptions) RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Com
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(o.OutputFormat) > 0 && o.OutputFormat != "name" {
|
printer, err := o.ToPrinter(patchOperation(didPatch))
|
||||||
return cmdutil.PrintObject(cmd, info.Object, out)
|
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 object was not successfully patched, exit with error code 1
|
||||||
if !didPatch {
|
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" {
|
printer, err := o.ToPrinter(patchOperation(didPatch))
|
||||||
return cmdutil.PrintObject(cmd, info.Object, out)
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
return printer.PrintObj(info.AsVersioned(), out)
|
||||||
cmdutil.PrintSuccess(o.OutputFormat == "name", out, info.Object, o.DryRun, patchOperation(didPatch))
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -144,7 +144,7 @@ func TestPatchNoop(t *testing.T) {
|
|||||||
cmd.Flags().Set("namespace", "test")
|
cmd.Flags().Set("namespace", "test")
|
||||||
cmd.Flags().Set("patch", `{"metadata":{"annotations":{"foo":"bar"}}}`)
|
cmd.Flags().Set("patch", `{"metadata":{"annotations":{"foo":"bar"}}}`)
|
||||||
cmd.Run(cmd, []string{"services", "frontend"})
|
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())
|
t.Errorf("unexpected output: %s", buf.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@ args:
|
|||||||
- service/svc1
|
- service/svc1
|
||||||
namespace: "myproject"
|
namespace: "myproject"
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- configmap "cm1" edited
|
- configmap/cm1 edited
|
||||||
- service "svc1" edited
|
- service/svc1 edited
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: request
|
- type: request
|
||||||
|
@ -5,8 +5,8 @@ args:
|
|||||||
- service/svc1
|
- service/svc1
|
||||||
namespace: "myproject"
|
namespace: "myproject"
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- configmap "cm1" edited
|
- configmap/cm1 edited
|
||||||
- service "svc1" edited
|
- service/svc1 edited
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: request
|
- type: request
|
||||||
|
@ -4,7 +4,7 @@ args:
|
|||||||
- service/svc1
|
- service/svc1
|
||||||
namespace: myproject
|
namespace: myproject
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- "service \"svc1\" edited"
|
- "service/svc1 edited"
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: request
|
- type: request
|
||||||
|
@ -6,7 +6,7 @@ args:
|
|||||||
outputFormat: yaml
|
outputFormat: yaml
|
||||||
namespace: myproject
|
namespace: myproject
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- service "svc1" edited
|
- service/svc1 edited
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: request
|
- type: request
|
||||||
|
@ -3,7 +3,7 @@ mode: create
|
|||||||
filename: "svc.yaml"
|
filename: "svc.yaml"
|
||||||
namespace: "edit-test"
|
namespace: "edit-test"
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- "service \"svc1\" created"
|
- "service/svc1 created"
|
||||||
expectedStderr:
|
expectedStderr:
|
||||||
- "\"svc2\" is invalid"
|
- "\"svc2\" is invalid"
|
||||||
expectedExitCode: 1
|
expectedExitCode: 1
|
||||||
|
@ -3,8 +3,8 @@ mode: create
|
|||||||
filename: "svc.yaml"
|
filename: "svc.yaml"
|
||||||
namespace: "edit-test"
|
namespace: "edit-test"
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- service "svc1" created
|
- service/svc1 created
|
||||||
- service "svc2" created
|
- service/svc2 created
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: edit
|
- type: edit
|
||||||
|
@ -5,7 +5,7 @@ args:
|
|||||||
- svc1
|
- svc1
|
||||||
namespace: edit-test
|
namespace: edit-test
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- service "svc1" edited
|
- service/svc1 edited
|
||||||
expectedStderr:
|
expectedStderr:
|
||||||
- "error: services \"svc1\" is invalid"
|
- "error: services \"svc1\" is invalid"
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
|
@ -11,7 +11,7 @@ outputPatch: "true"
|
|||||||
namespace: edit-test
|
namespace: edit-test
|
||||||
expectedStdout:
|
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"}}}'
|
- '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
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: request
|
- type: request
|
||||||
|
@ -4,8 +4,8 @@ args:
|
|||||||
- configmaps,services
|
- configmaps,services
|
||||||
namespace: "edit-test"
|
namespace: "edit-test"
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- configmap "cm1" edited
|
- configmap/cm1 edited
|
||||||
- service "svc1" edited
|
- service/svc1 edited
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: request
|
- type: request
|
||||||
|
@ -5,8 +5,8 @@ args:
|
|||||||
- service/svc1
|
- service/svc1
|
||||||
namespace: "edit-test"
|
namespace: "edit-test"
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- configmap "cm1" edited
|
- configmap/cm1 edited
|
||||||
- service "svc1" edited
|
- service/svc1 edited
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: request
|
- type: request
|
||||||
|
@ -5,8 +5,8 @@ args:
|
|||||||
- service/svc1
|
- service/svc1
|
||||||
namespace: "edit-test"
|
namespace: "edit-test"
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- configmap "cm1" edited
|
- configmap/cm1 edited
|
||||||
- service "svc1" edited
|
- service/svc1 edited
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: request
|
- type: request
|
||||||
|
@ -9,7 +9,7 @@ args:
|
|||||||
saveConfig: "false"
|
saveConfig: "false"
|
||||||
namespace: edit-test
|
namespace: edit-test
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- service "svc1" edited
|
- service/svc1 edited
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: request
|
- type: request
|
||||||
|
@ -6,9 +6,9 @@ args:
|
|||||||
- bars/test2
|
- bars/test2
|
||||||
namespace: default
|
namespace: default
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- "service \"kubernetes\" edited"
|
- "service/kubernetes edited"
|
||||||
- "bar.company.com \"test\" edited"
|
- "bar.company.com/test edited"
|
||||||
- "bar.company.com \"test2\" edited"
|
- "bar.company.com/test2 edited"
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: request
|
- type: request
|
||||||
|
@ -8,7 +8,7 @@ args:
|
|||||||
- svc1
|
- svc1
|
||||||
namespace: edit-test
|
namespace: edit-test
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- service "svc1" edited
|
- service/svc1 edited
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: request
|
- type: request
|
||||||
|
@ -4,7 +4,7 @@ args:
|
|||||||
- service/kubernetes
|
- service/kubernetes
|
||||||
namespace: default
|
namespace: default
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- "service \"kubernetes\" edited"
|
- "service/kubernetes edited"
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: request
|
- type: request
|
||||||
|
@ -4,7 +4,7 @@ args:
|
|||||||
- storageclasses.v1beta1.storage.k8s.io/foo
|
- storageclasses.v1beta1.storage.k8s.io/foo
|
||||||
namespace: default
|
namespace: default
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- "storageclass.storage.k8s.io \"foo\" edited"
|
- "storageclass.storage.k8s.io/foo edited"
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: request
|
- type: request
|
||||||
|
@ -4,7 +4,7 @@ args:
|
|||||||
- storageclasses.v0.storage.k8s.io/foo
|
- storageclasses.v0.storage.k8s.io/foo
|
||||||
namespace: default
|
namespace: default
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- "storageclass.storage.k8s.io \"foo\" edited"
|
- "storageclass.storage.k8s.io/foo edited"
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: request
|
- type: request
|
||||||
|
@ -9,7 +9,7 @@ args:
|
|||||||
saveConfig: "true"
|
saveConfig: "true"
|
||||||
namespace: edit-test
|
namespace: edit-test
|
||||||
expectedStdout:
|
expectedStdout:
|
||||||
- service "svc1" edited
|
- service/svc1 edited
|
||||||
expectedExitCode: 0
|
expectedExitCode: 0
|
||||||
steps:
|
steps:
|
||||||
- type: request
|
- type: request
|
||||||
|
@ -57,6 +57,9 @@ type EditOptions struct {
|
|||||||
resource.FilenameOptions
|
resource.FilenameOptions
|
||||||
RecordFlags *genericclioptions.RecordFlags
|
RecordFlags *genericclioptions.RecordFlags
|
||||||
|
|
||||||
|
PrintFlags *printers.PrintFlags
|
||||||
|
ToPrinter func(string) (printers.ResourcePrinterFunc, error)
|
||||||
|
|
||||||
Output string
|
Output string
|
||||||
OutputPatch bool
|
OutputPatch bool
|
||||||
WindowsLineEndings bool
|
WindowsLineEndings bool
|
||||||
@ -86,12 +89,14 @@ func NewEditOptions(editMode EditMode, ioStreams genericclioptions.IOStreams) *E
|
|||||||
|
|
||||||
EditMode: editMode,
|
EditMode: editMode,
|
||||||
|
|
||||||
Output: "yaml",
|
PrintFlags: printers.NewPrintFlags("edited"),
|
||||||
|
|
||||||
WindowsLineEndings: goruntime.GOOS == "windows",
|
WindowsLineEndings: goruntime.GOOS == "windows",
|
||||||
|
|
||||||
Recorder: genericclioptions.NoopRecorder{},
|
Recorder: genericclioptions.NoopRecorder{},
|
||||||
|
|
||||||
IOStreams: ioStreams,
|
IOStreams: ioStreams,
|
||||||
|
Output: "yaml",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,6 +164,15 @@ func (o *EditOptions) Complete(f cmdutil.Factory, args []string, cmd *cobra.Comm
|
|||||||
Do()
|
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.CmdNamespace = cmdNamespace
|
||||||
o.f = f
|
o.f = f
|
||||||
|
|
||||||
@ -423,14 +437,23 @@ func (o *EditOptions) visitToApplyEditPatch(originalInfos []*resource.Info, patc
|
|||||||
}
|
}
|
||||||
|
|
||||||
if reflect.DeepEqual(originalJS, editedJS) {
|
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
|
return nil
|
||||||
} else {
|
} else {
|
||||||
err := o.annotationPatch(info)
|
err := o.annotationPatch(info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -549,7 +572,11 @@ func (o *EditOptions) visitToPatch(originalInfos []*resource.Info, patchVisitor
|
|||||||
|
|
||||||
if reflect.DeepEqual(originalJS, editedJS) {
|
if reflect.DeepEqual(originalJS, editedJS) {
|
||||||
// no edit, so just skip it.
|
// 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -603,7 +630,11 @@ func (o *EditOptions) visitToPatch(originalInfos []*resource.Info, patchVisitor
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
info.Refresh(patched, true)
|
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 nil
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
@ -614,7 +645,11 @@ func (o *EditOptions) visitToCreate(createVisitor resource.Visitor) error {
|
|||||||
if err := resource.CreateAndRefresh(info); err != nil {
|
if err := resource.CreateAndRefresh(info); err != nil {
|
||||||
return err
|
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 nil
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
|
@ -23,11 +23,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type NoCompatiblePrinterError struct {
|
type NoCompatiblePrinterError struct {
|
||||||
|
OutputFormat *string
|
||||||
Options interface{}
|
Options interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e NoCompatiblePrinterError) Error() string {
|
func (e NoCompatiblePrinterError) Error() string {
|
||||||
return fmt.Sprintf("unable to match a printer suitable for the options specified: %#v", e.Options)
|
output := ""
|
||||||
|
if e.OutputFormat != nil {
|
||||||
|
output = *e.OutputFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("unable to match a printer suitable for the output format %q and the options specified: %#v", output, e.Options)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsNoCompatiblePrinterError(err error) bool {
|
func IsNoCompatiblePrinterError(err error) bool {
|
||||||
@ -67,7 +73,7 @@ func (f *PrintFlags) ToPrinter() (ResourcePrinter, error) {
|
|||||||
return p, err
|
return p, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, NoCompatiblePrinterError{f}
|
return nil, NoCompatiblePrinterError{Options: f, OutputFormat: f.OutputFormat}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *PrintFlags) AddFlags(cmd *cobra.Command) {
|
func (f *PrintFlags) AddFlags(cmd *cobra.Command) {
|
||||||
@ -79,6 +85,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 {
|
func NewPrintFlags(operation string) *PrintFlags {
|
||||||
outputFormat := ""
|
outputFormat := ""
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ func (f *JSONYamlPrintFlags) ToPrinter(outputFormat string) (ResourcePrinter, er
|
|||||||
case "yaml":
|
case "yaml":
|
||||||
printer = &YAMLPrinter{}
|
printer = &YAMLPrinter{}
|
||||||
default:
|
default:
|
||||||
return nil, NoCompatiblePrinterError{f}
|
return nil, NoCompatiblePrinterError{Options: f, OutputFormat: &outputFormat}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wrap the printer in a versioning printer that understands when to convert and when not to convert
|
// wrap the printer in a versioning printer that understands when to convert and when not to convert
|
||||||
|
@ -39,7 +39,7 @@ type JSONPathPrintFlags struct {
|
|||||||
// Returns false if the specified templateFormat does not match a template format.
|
// Returns false if the specified templateFormat does not match a template format.
|
||||||
func (f *JSONPathPrintFlags) ToPrinter(templateFormat string) (ResourcePrinter, error) {
|
func (f *JSONPathPrintFlags) ToPrinter(templateFormat string) (ResourcePrinter, error) {
|
||||||
if (f.TemplateArgument == nil || len(*f.TemplateArgument) == 0) && len(templateFormat) == 0 {
|
if (f.TemplateArgument == nil || len(*f.TemplateArgument) == 0) && len(templateFormat) == 0 {
|
||||||
return nil, NoCompatiblePrinterError{f}
|
return nil, NoCompatiblePrinterError{Options: f, OutputFormat: &templateFormat}
|
||||||
}
|
}
|
||||||
|
|
||||||
templateValue := ""
|
templateValue := ""
|
||||||
@ -66,7 +66,7 @@ func (f *JSONPathPrintFlags) ToPrinter(templateFormat string) (ResourcePrinter,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if _, supportedFormat := templateFormats[templateFormat]; !supportedFormat {
|
if _, supportedFormat := templateFormats[templateFormat]; !supportedFormat {
|
||||||
return nil, NoCompatiblePrinterError{f}
|
return nil, NoCompatiblePrinterError{Options: f, OutputFormat: &templateFormat}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(templateValue) == 0 {
|
if len(templateValue) == 0 {
|
||||||
|
@ -63,7 +63,7 @@ func (f *NamePrintFlags) ToPrinter(outputFormat string) (ResourcePrinter, error)
|
|||||||
case "":
|
case "":
|
||||||
return namePrinter, nil
|
return namePrinter, nil
|
||||||
default:
|
default:
|
||||||
return nil, NoCompatiblePrinterError{f}
|
return nil, NoCompatiblePrinterError{Options: f, OutputFormat: &outputFormat}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ type GoTemplatePrintFlags struct {
|
|||||||
// Returns false if the specified templateFormat does not match a template format.
|
// Returns false if the specified templateFormat does not match a template format.
|
||||||
func (f *GoTemplatePrintFlags) ToPrinter(templateFormat string) (ResourcePrinter, error) {
|
func (f *GoTemplatePrintFlags) ToPrinter(templateFormat string) (ResourcePrinter, error) {
|
||||||
if (f.TemplateArgument == nil || len(*f.TemplateArgument) == 0) && len(templateFormat) == 0 {
|
if (f.TemplateArgument == nil || len(*f.TemplateArgument) == 0) && len(templateFormat) == 0 {
|
||||||
return nil, NoCompatiblePrinterError{f}
|
return nil, NoCompatiblePrinterError{Options: f, OutputFormat: &templateFormat}
|
||||||
}
|
}
|
||||||
|
|
||||||
templateValue := ""
|
templateValue := ""
|
||||||
@ -68,7 +68,7 @@ func (f *GoTemplatePrintFlags) ToPrinter(templateFormat string) (ResourcePrinter
|
|||||||
}
|
}
|
||||||
|
|
||||||
if _, supportedFormat := supportedFormats[templateFormat]; !supportedFormat {
|
if _, supportedFormat := supportedFormats[templateFormat]; !supportedFormat {
|
||||||
return nil, NoCompatiblePrinterError{f}
|
return nil, NoCompatiblePrinterError{Options: f, OutputFormat: &templateFormat}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(templateValue) == 0 {
|
if len(templateValue) == 0 {
|
||||||
|
Loading…
Reference in New Issue
Block a user