Remove Factory from more Run commands

This commit is contained in:
Maciej Szulik 2018-04-26 15:30:21 +02:00
parent 03c5f298f3
commit b7d4f15965
No known key found for this signature in database
GPG Key ID: F15E55D276FA84C4
19 changed files with 611 additions and 642 deletions

View File

@ -3132,7 +3132,7 @@ run_deployment_tests() {
# Set env of deployments for all container
kubectl set env deployment nginx-deployment env=prod "${kube_flags[@]}"
# Set env of deployments for specific container
kubectl set env deployment nginx-deployment env=prod -c=nginx "${kube_flags[@]}"
kubectl set env deployment nginx-deployment superenv=superprod -c=nginx "${kube_flags[@]}"
# Set env of deployments by configmap
kubectl set env deployment nginx-deployment --from=configmap/test-set-env-config "${kube_flags[@]}"
# Set env of deployments by secret

View File

@ -63,6 +63,11 @@ type AnnotateOptions struct {
newAnnotations map[string]string
removeAnnotations []string
Recorder genericclioptions.Recorder
namespace string
enforceNamespace bool
builder *resource.Builder
unstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
includeUninitialized bool
genericclioptions.IOStreams
}
@ -123,13 +128,9 @@ func NewCmdAnnotate(parent string, f cmdutil.Factory, ioStreams genericclioption
Long: annotateLong + "\n\n" + cmdutil.SuggestApiResources(parent),
Example: annotateExample,
Run: func(cmd *cobra.Command, args []string) {
if err := o.Complete(f, cmd, args); err != nil {
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, "%v", err))
}
if err := o.Validate(); err != nil {
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, "%v", err))
}
cmdutil.CheckErr(o.RunAnnotate(f, cmd))
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.RunAnnotate())
},
ValidArgs: validArgs,
ArgAliases: kubectl.ResourceAliases(validArgs),
@ -176,6 +177,14 @@ func (o *AnnotateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
return printer.PrintObj(obj, out)
}
o.namespace, o.enforceNamespace, err = f.DefaultNamespace()
if err != nil {
return err
}
o.includeUninitialized = cmdutil.ShouldIncludeUninitialized(cmd, false)
o.builder = f.NewBuilder()
o.unstructuredClientForMapping = f.UnstructuredClientForMapping
// retrieves resource and annotation args from args
// also checks args to verify that all resources are specified before annotations
resources, annotationArgs, err := cmdutil.GetResourcesAndPairs(args, "annotation")
@ -184,9 +193,13 @@ func (o *AnnotateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
}
o.resources = resources
o.newAnnotations, o.removeAnnotations, err = parseAnnotations(annotationArgs)
if err != nil {
return err
}
return nil
}
// Validate checks to the AnnotateOptions to see if there is sufficient information run the command.
func (o AnnotateOptions) Validate() error {
if o.all && len(o.selector) > 0 {
@ -202,20 +215,14 @@ func (o AnnotateOptions) Validate() error {
}
// RunAnnotate does the work
func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) error {
namespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil {
return err
}
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
b := f.NewBuilder().
func (o AnnotateOptions) RunAnnotate() error {
b := o.builder.
Unstructured().
LocalParam(o.local).
ContinueOnError().
NamespaceParam(namespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
IncludeUninitialized(includeUninitialized).
NamespaceParam(o.namespace).DefaultNamespace().
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
IncludeUninitialized(o.includeUninitialized).
Flatten()
if !o.local {
@ -276,7 +283,7 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
}
mapping := info.ResourceMapping()
client, err := f.UnstructuredClientForMapping(mapping)
client, err := o.unstructuredClientForMapping(mapping)
if err != nil {
return err
}

View File

@ -499,7 +499,7 @@ func TestAnnotateObject(t *testing.T) {
if err := options.Validate(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if err := options.RunAnnotate(tf, cmd); err != nil {
if err := options.RunAnnotate(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
@ -554,7 +554,7 @@ func TestAnnotateObjectFromFile(t *testing.T) {
if err := options.Validate(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if err := options.RunAnnotate(tf, cmd); err != nil {
if err := options.RunAnnotate(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
@ -586,7 +586,7 @@ func TestAnnotateLocal(t *testing.T) {
if err := options.Validate(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if err := options.RunAnnotate(tf, cmd); err != nil {
if err := options.RunAnnotate(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
@ -642,7 +642,7 @@ func TestAnnotateMultipleObjects(t *testing.T) {
if err := options.Validate(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if err := options.RunAnnotate(tf, cmd); err != nil {
if err := options.RunAnnotate(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
}

View File

@ -18,14 +18,15 @@ package cmd
import (
"fmt"
"io"
"sort"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/discovery"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
)
@ -35,37 +36,54 @@ var (
kubectl api-versions`))
)
func NewCmdApiVersions(f cmdutil.Factory, out io.Writer) *cobra.Command {
type ApiVersionsOptions struct {
discoveryClient discovery.CachedDiscoveryInterface
genericclioptions.IOStreams
}
func NewApiVersionsOptions(ioStreams genericclioptions.IOStreams) *ApiVersionsOptions {
return &ApiVersionsOptions{
IOStreams: ioStreams,
}
}
func NewCmdApiVersions(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
o := NewApiVersionsOptions(ioStreams)
cmd := &cobra.Command{
Use: "api-versions",
Short: "Print the supported API versions on the server, in the form of \"group/version\"",
Long: "Print the supported API versions on the server, in the form of \"group/version\"",
Example: apiversionsExample,
Run: func(cmd *cobra.Command, args []string) {
err := RunApiVersions(f, out)
cmdutil.CheckErr(err)
cmdutil.CheckErr(o.Complete(f))
cmdutil.CheckErr(o.RunApiVersions())
},
}
return cmd
}
func RunApiVersions(f cmdutil.Factory, w io.Writer) error {
discoveryclient, err := f.DiscoveryClient()
func (o *ApiVersionsOptions) Complete(f cmdutil.Factory) error {
var err error
o.discoveryClient, err = f.DiscoveryClient()
if err != nil {
return err
}
return nil
}
func (o *ApiVersionsOptions) RunApiVersions() error {
// Always request fresh data from the server
discoveryclient.Invalidate()
o.discoveryClient.Invalidate()
groupList, err := discoveryclient.ServerGroups()
groupList, err := o.discoveryClient.ServerGroups()
if err != nil {
return fmt.Errorf("Couldn't get available api versions from server: %v\n", err)
}
apiVersions := metav1.ExtractGroupVersions(groupList)
sort.Strings(apiVersions)
for _, v := range apiVersions {
fmt.Fprintln(w, v)
fmt.Fprintln(o.Out, v)
}
return nil
}

View File

@ -18,19 +18,14 @@ package cmd
import (
"bytes"
"encoding/json"
"fmt"
"io"
"github.com/ghodss/yaml"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
apijson "k8s.io/apimachinery/pkg/util/json"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -39,21 +34,27 @@ import (
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/kubectl/scheme"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/printers"
)
type SetLastAppliedOptions struct {
FilenameOptions resource.FilenameOptions
Selector string
InfoList []*resource.Info
Mapper meta.RESTMapper
Namespace string
EnforceNamespace bool
DryRun bool
ShortOutput bool
CreateAnnotation bool
Output string
PatchBufferList []PatchBuffer
Factory cmdutil.Factory
PrintFlags *printers.PrintFlags
PrintObj printers.ResourcePrinterFunc
FilenameOptions resource.FilenameOptions
infoList []*resource.Info
mapper meta.RESTMapper
namespace string
enforceNamespace bool
dryRun bool
shortOutput bool
output string
patchBufferList []PatchBuffer
builder *resource.Builder
unstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
genericclioptions.IOStreams
}
@ -83,12 +84,13 @@ var (
func NewSetLastAppliedOptions(ioStreams genericclioptions.IOStreams) *SetLastAppliedOptions {
return &SetLastAppliedOptions{
PrintFlags: printers.NewPrintFlags("configured"),
IOStreams: ioStreams,
}
}
func NewCmdApplySetLastApplied(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
options := NewSetLastAppliedOptions(ioStreams)
o := NewSetLastAppliedOptions(ioStreams)
cmd := &cobra.Command{
Use: "set-last-applied -f FILENAME",
DisableFlagsInUseLine: true,
@ -96,38 +98,55 @@ func NewCmdApplySetLastApplied(f cmdutil.Factory, ioStreams genericclioptions.IO
Long: applySetLastAppliedLong,
Example: applySetLastAppliedExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(f, cmd))
cmdutil.CheckErr(options.Validate(f, cmd))
cmdutil.CheckErr(options.RunSetLastApplied(f, cmd))
cmdutil.CheckErr(o.Complete(f, cmd))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.RunSetLastApplied())
},
}
cmdutil.AddDryRunFlag(cmd)
cmdutil.AddPrinterFlags(cmd)
cmd.Flags().BoolVar(&options.CreateAnnotation, "create-annotation", options.CreateAnnotation, "Will create 'last-applied-configuration' annotations if current objects doesn't have one")
usage := "that contains the last-applied-configuration annotations"
kubectl.AddJsonFilenameFlag(cmd, &options.FilenameOptions.Filenames, "Filename, directory, or URL to files "+usage)
cmd.Flags().BoolVar(&o.CreateAnnotation, "create-annotation", o.CreateAnnotation, "Will create 'last-applied-configuration' annotations if current objects doesn't have one")
kubectl.AddJsonFilenameFlag(cmd, &o.FilenameOptions.Filenames, "Filename, directory, or URL to files that contains the last-applied-configuration annotations")
return cmd
}
func (o *SetLastAppliedOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
o.DryRun = cmdutil.GetDryRunFlag(cmd)
o.Output = cmdutil.GetFlagString(cmd, "output")
o.ShortOutput = o.Output == "name"
o.Mapper = f.RESTMapper()
o.dryRun = cmdutil.GetDryRunFlag(cmd)
o.output = cmdutil.GetFlagString(cmd, "output")
o.shortOutput = o.output == "name"
o.mapper = f.RESTMapper()
var err error
o.Namespace, o.EnforceNamespace, err = f.DefaultNamespace()
o.namespace, o.enforceNamespace, err = f.DefaultNamespace()
if err != nil {
return err
}
o.builder = f.NewBuilder()
o.unstructuredClientForMapping = f.UnstructuredClientForMapping
func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command) error {
r := f.NewBuilder().
if o.dryRun {
// TODO(juanvallejo): This can be cleaned up even further by creating
// a PrintFlags struct that binds the --dry-run flag, and whose
// ToPrinter method returns a printer that understands how to print
// this success message.
o.PrintFlags.Complete("%s (dry run)")
}
printer, err := o.PrintFlags.ToPrinter()
if err != nil {
return err
}
o.PrintObj = printer.PrintObj
return nil
}
func (o *SetLastAppliedOptions) Validate() error {
r := o.builder.
Unstructured().
NamespaceParam(o.Namespace).DefaultNamespace().
FilenameParam(o.EnforceNamespace, &o.FilenameOptions).
NamespaceParam(o.namespace).DefaultNamespace().
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
Flatten().
Do()
@ -153,14 +172,14 @@ func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command)
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%s\nfrom server for:", info.String()), info.Source, err)
}
if originalBuf == nil && !o.CreateAnnotation {
return cmdutil.UsageErrorf(cmd, "no last-applied-configuration annotation found on resource: %s, to create the annotation, run the command with --create-annotation", info.Name)
return fmt.Errorf("no last-applied-configuration annotation found on resource: %s, to create the annotation, run the command with --create-annotation", info.Name)
}
//only add to PatchBufferList when changed
if !bytes.Equal(cmdutil.StripComments(originalBuf), cmdutil.StripComments(diffBuf)) {
p := PatchBuffer{Patch: patchBuf, PatchType: patchType}
o.PatchBufferList = append(o.PatchBufferList, p)
o.InfoList = append(o.InfoList, info)
o.patchBufferList = append(o.patchBufferList, p)
o.infoList = append(o.infoList, info)
} else {
fmt.Fprintf(o.Out, "set-last-applied %s: no changes required.\n", info.Name)
}
@ -170,68 +189,25 @@ func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command)
return err
}
func (o *SetLastAppliedOptions) RunSetLastApplied(f cmdutil.Factory, cmd *cobra.Command) error {
for i, patch := range o.PatchBufferList {
info := o.InfoList[i]
if !o.DryRun {
func (o *SetLastAppliedOptions) RunSetLastApplied() error {
for i, patch := range o.patchBufferList {
info := o.infoList[i]
if !o.dryRun {
mapping := info.ResourceMapping()
client, err := f.UnstructuredClientForMapping(mapping)
client, err := o.unstructuredClientForMapping(mapping)
if err != nil {
return err
}
helper := resource.NewHelper(client, mapping)
patchedObj, err := helper.Patch(o.Namespace, info.Name, patch.PatchType, patch.Patch)
patchedObj, err := helper.Patch(o.namespace, info.Name, patch.PatchType, patch.Patch)
if err != nil {
return err
}
if len(o.Output) > 0 && !o.ShortOutput {
info.Refresh(patchedObj, false)
return cmdutil.PrintObject(cmd, info.Object, o.Out)
}
cmdutil.PrintSuccess(o.ShortOutput, o.Out, info.Object, o.DryRun, "configured")
} else {
err := o.formatPrinter(o.Output, patch.Patch, o.Out)
if err != nil {
if err := o.PrintObj(info.AsVersioned(legacyscheme.Scheme), o.Out); err != nil {
return err
}
cmdutil.PrintSuccess(o.ShortOutput, o.Out, info.Object, o.DryRun, "configured")
}
}
return nil
}
func (o *SetLastAppliedOptions) formatPrinter(output string, buf []byte, w io.Writer) error {
yamlOutput, err := yaml.JSONToYAML(buf)
if err != nil {
return err
}
switch output {
case "json":
jsonBuffer := &bytes.Buffer{}
err = json.Indent(jsonBuffer, buf, "", " ")
if err != nil {
return err
}
fmt.Fprintf(w, "%s\n", jsonBuffer.String())
case "yaml":
fmt.Fprintf(w, "%s\n", string(yamlOutput))
}
return nil
}
func (o *SetLastAppliedOptions) getPatch(info *resource.Info) ([]byte, []byte, error) {
objMap := map[string]map[string]map[string]string{}
metadataMap := map[string]map[string]string{}
annotationsMap := map[string]string{}
localFile, err := runtime.Encode(scheme.DefaultJSONEncoder(), info.Object)
if err != nil {
return nil, localFile, err
}
annotationsMap[api.LastAppliedConfigAnnotation] = string(localFile)
metadataMap["annotations"] = annotationsMap
objMap["metadata"] = metadataMap
jsonString, err := apijson.Marshal(objMap)
return jsonString, localFile, err
}

View File

@ -1121,7 +1121,7 @@ func TestRunApplySetLastApplied(t *testing.T) {
name: "set with exist object",
filePath: filenameRC,
expectedErr: "",
expectedOut: "replicationcontroller/test-rc\n",
expectedOut: "replicationcontroller/test-rc configured\n",
output: "name",
},
{
@ -1134,7 +1134,7 @@ func TestRunApplySetLastApplied(t *testing.T) {
{
name: "set for the annotation does not exist on the live object",
filePath: filenameRCNoAnnotation,
expectedErr: "error: no last-applied-configuration annotation found on resource: no-annotation, to create the annotation, run the command with --create-annotation\nSee 'set-last-applied -h' for help and examples.",
expectedErr: "error: no last-applied-configuration annotation found on resource: no-annotation, to create the annotation, run the command with --create-annotation",
expectedOut: "",
output: "name",
},
@ -1142,14 +1142,14 @@ func TestRunApplySetLastApplied(t *testing.T) {
name: "set with exist object output json",
filePath: filenameRCJSON,
expectedErr: "",
expectedOut: "replicationcontroller/test-rc\n",
expectedOut: "replicationcontroller/test-rc configured\n",
output: "name",
},
{
name: "set test for a directory of files",
filePath: dirName,
expectedErr: "",
expectedOut: "replicationcontroller/test-rc\nreplicationcontroller/test-rc\n",
expectedOut: "replicationcontroller/test-rc configured\nreplicationcontroller/test-rc configured\n",
output: "name",
},
}

View File

@ -24,7 +24,6 @@ import (
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
@ -59,20 +58,22 @@ type AutoscaleOptions struct {
PrintFlags *printers.PrintFlags
ToPrinter func(string) (printers.ResourcePrinterFunc, error)
Builder *resource.Builder
CanBeAutoscaled func(kind schema.GroupKind) error
Name string
Generator string
Min int32
Max int32
CpuPercent int32
CreateAnnotation bool
DryRun bool
EnforceNamespace bool
Mapper meta.RESTMapper
ClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
GeneratorFunc func(string, *meta.RESTMapping) (kubectl.StructuredGenerator, error)
Namespace string
BuilderArgs []string
createAnnotation bool
args []string
enforceNamespace bool
namespace string
dryRun bool
builder *resource.Builder
mapper meta.RESTMapper
canBeAutoscaled func(kind schema.GroupKind) error
clientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
generatorFunc func(string, *meta.RESTMapping) (kubectl.StructuredGenerator, error)
genericclioptions.IOStreams
}
@ -102,7 +103,7 @@ func NewCmdAutoscale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *
Example: autoscaleExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate(cmd))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run())
},
ValidArgs: validArgs,
@ -113,27 +114,26 @@ func NewCmdAutoscale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *
o.RecordFlags.AddFlags(cmd)
o.PrintFlags.AddFlags(cmd)
cmd.Flags().String("generator", cmdutil.HorizontalPodAutoscalerV1GeneratorName, i18n.T("The name of the API generator to use. Currently there is only 1 generator."))
cmd.Flags().Int32("min", -1, "The lower limit for the number of pods that can be set by the autoscaler. If it's not specified or negative, the server will apply a default value.")
cmd.Flags().Int32("max", -1, "The upper limit for the number of pods that can be set by the autoscaler. Required.")
cmd.Flags().StringVar(&o.Generator, "generator", cmdutil.HorizontalPodAutoscalerV1GeneratorName, i18n.T("The name of the API generator to use. Currently there is only 1 generator."))
cmd.Flags().Int32Var(&o.Min, "min", -1, "The lower limit for the number of pods that can be set by the autoscaler. If it's not specified or negative, the server will apply a default value.")
cmd.Flags().Int32Var(&o.Max, "max", -1, "The upper limit for the number of pods that can be set by the autoscaler. Required.")
cmd.MarkFlagRequired("max")
cmd.Flags().Int32("cpu-percent", -1, fmt.Sprintf("The target average CPU utilization (represented as a percent of requested CPU) over all the pods. If it's not specified or negative, a default autoscaling policy will be used."))
cmd.Flags().String("name", "", i18n.T("The name for the newly created object. If not specified, the name of the input resource will be used."))
cmd.Flags().Int32Var(&o.CpuPercent, "cpu-percent", -1, fmt.Sprintf("The target average CPU utilization (represented as a percent of requested CPU) over all the pods. If it's not specified or negative, a default autoscaling policy will be used."))
cmd.Flags().StringVar(&o.Name, "name", "", i18n.T("The name for the newly created object. If not specified, the name of the input resource will be used."))
cmdutil.AddDryRunFlag(cmd)
usage := "identifying the resource to autoscale."
cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, usage)
cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, "identifying the resource to autoscale.")
cmdutil.AddApplyAnnotationFlags(cmd)
return cmd
}
func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
o.DryRun = cmdutil.GetFlagBool(cmd, "dry-run")
o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
o.Builder = f.NewBuilder()
o.CanBeAutoscaled = f.CanBeAutoscaled
o.Mapper = f.RESTMapper()
o.ClientForMapping = f.ClientForMapping
o.BuilderArgs = args
o.dryRun = cmdutil.GetFlagBool(cmd, "dry-run")
o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
o.builder = f.NewBuilder()
o.canBeAutoscaled = f.CanBeAutoscaled
o.mapper = f.RESTMapper()
o.clientForMapping = f.ClientForMapping
o.args = args
o.RecordFlags.Complete(f.Command(cmd, false))
var err error
@ -143,34 +143,31 @@ func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
}
// 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 {
o.generatorFunc = func(name string, mapping *meta.RESTMapping) (kubectl.StructuredGenerator, error) {
switch o.Generator {
case cmdutil.HorizontalPodAutoscalerV1GeneratorName:
generator = &kubectl.HorizontalPodAutoscalerGeneratorV1{
return &kubectl.HorizontalPodAutoscalerGeneratorV1{
Name: name,
MinReplicas: cmdutil.GetFlagInt32(cmd, "min"),
MaxReplicas: cmdutil.GetFlagInt32(cmd, "max"),
CPUPercent: cmdutil.GetFlagInt32(cmd, "cpu-percent"),
MinReplicas: o.Min,
MaxReplicas: o.Max,
CPUPercent: o.CpuPercent,
ScaleRefName: name,
ScaleRefKind: mapping.GroupVersionKind.Kind,
ScaleRefApiVersion: mapping.GroupVersionKind.GroupVersion().String(),
}
}, nil
default:
return nil, cmdutil.UsageErrorf(cmd, "Generator %s not supported. ", generatorName)
return nil, cmdutil.UsageErrorf(cmd, "Generator %s not supported. ", o.Generator)
}
}
return generator, nil
}
o.Namespace, o.EnforceNamespace, err = f.DefaultNamespace()
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 {
if o.dryRun {
o.PrintFlags.Complete("%s (dry run)")
}
@ -185,21 +182,24 @@ func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
return nil
}
func (o *AutoscaleOptions) Validate(cmd *cobra.Command) error {
if err := validateFlags(cmd); err != nil {
return err
func (o *AutoscaleOptions) Validate() error {
if o.Max < 1 {
return fmt.Errorf("--max=MAXPODS is required and must be at least 1, max: %d", o.Max)
}
if o.Max < o.Min {
return fmt.Errorf("--max=MAXPODS must be larger or equal to --min=MINPODS, max: %d, min: %d", o.Max, o.Min)
}
return nil
}
func (o *AutoscaleOptions) Run() error {
r := o.Builder.
r := o.builder.
Internal(legacyscheme.Scheme).
ContinueOnError().
NamespaceParam(o.Namespace).DefaultNamespace().
FilenameParam(o.EnforceNamespace, o.FilenameOptions).
ResourceTypeOrNameArgs(false, o.BuilderArgs...).
NamespaceParam(o.namespace).DefaultNamespace().
FilenameParam(o.enforceNamespace, o.FilenameOptions).
ResourceTypeOrNameArgs(false, o.args...).
Flatten().
Do()
if err := r.Err(); err != nil {
@ -213,11 +213,11 @@ func (o *AutoscaleOptions) Run() error {
}
mapping := info.ResourceMapping()
if err := o.CanBeAutoscaled(mapping.GroupVersionKind.GroupKind()); err != nil {
if err := o.canBeAutoscaled(mapping.GroupVersionKind.GroupKind()); err != nil {
return err
}
generator, err := o.GeneratorFunc(info.Name, mapping)
generator, err := o.generatorFunc(info.Name, mapping)
if err != nil {
return err
}
@ -229,8 +229,8 @@ func (o *AutoscaleOptions) Run() error {
}
resourceMapper := &resource.Mapper{
RESTMapper: o.Mapper,
ClientMapper: resource.ClientMapperFunc(o.ClientForMapping),
RESTMapper: o.mapper,
ClientMapper: resource.ClientMapperFunc(o.clientForMapping),
Decoder: cmdutil.InternalVersionDecoder(),
}
hpa, err := resourceMapper.InfoForObject(object, legacyscheme.Scheme, nil)
@ -242,7 +242,7 @@ func (o *AutoscaleOptions) Run() error {
}
object = hpa.Object
if o.DryRun {
if o.dryRun {
count++
printer, err := o.ToPrinter("created")
@ -252,11 +252,11 @@ func (o *AutoscaleOptions) Run() error {
return printer.PrintObj(hpa.AsVersioned(legacyscheme.Scheme), o.Out)
}
if err := kubectl.CreateOrUpdateAnnotation(o.CreateAnnotation, hpa.Object, cmdutil.InternalVersionJSONEncoder()); err != nil {
if err := kubectl.CreateOrUpdateAnnotation(o.createAnnotation, hpa.Object, cmdutil.InternalVersionJSONEncoder()); err != nil {
return err
}
_, err = resource.NewHelper(hpa.Client, hpa.Mapping).Create(o.Namespace, false, object)
_, err = resource.NewHelper(hpa.Client, hpa.Mapping).Create(o.namespace, false, object)
if err != nil {
return err
}
@ -276,15 +276,3 @@ func (o *AutoscaleOptions) Run() error {
}
return nil
}
func validateFlags(cmd *cobra.Command) error {
errs := []error{}
max, min := cmdutil.GetFlagInt32(cmd, "max"), cmdutil.GetFlagInt32(cmd, "min")
if max < 1 {
errs = append(errs, fmt.Errorf("--max=MAXPODS is required and must be at least 1, max: %d", max))
}
if max < min {
errs = append(errs, fmt.Errorf("--max=MAXPODS must be larger or equal to --min=MINPODS, max: %d, min: %d", max, min))
}
return utilerrors.NewAggregate(errs)
}

View File

@ -21,11 +21,15 @@ import (
"io"
"os"
"path"
"time"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
restclient "k8s.io/client-go/rest"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
@ -37,6 +41,15 @@ type ClusterInfoDumpOptions struct {
PrintFlags *printers.PrintFlags
PrintObj printers.ResourcePrinterFunc
OutputDir string
AllNamespaces bool
Namespaces []string
timeout time.Duration
clientset internalclientset.Interface
namespace string
logsForObject func(object, options runtime.Object, timeout time.Duration) (*restclient.Request, error)
genericclioptions.IOStreams
}
@ -54,13 +67,13 @@ func NewCmdClusterInfoDump(f cmdutil.Factory, ioStreams genericclioptions.IOStre
Long: dumpLong,
Example: dumpExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete())
cmdutil.CheckErr(o.Run(f, cmd))
cmdutil.CheckErr(o.Complete(f, cmd))
cmdutil.CheckErr(o.Run())
},
}
cmd.Flags().String("output-directory", "", i18n.T("Where to output the files. If empty or '-' uses stdout, otherwise creates a directory hierarchy in that directory"))
cmd.Flags().StringSlice("namespaces", []string{}, "A comma separated list of namespaces to dump.")
cmd.Flags().Bool("all-namespaces", false, "If true, dump all namespaces. If true, --namespaces is ignored.")
cmd.Flags().StringVar(&o.OutputDir, "output-directory", "", i18n.T("Where to output the files. If empty or '-' uses stdout, otherwise creates a directory hierarchy in that directory"))
cmd.Flags().StringSliceVar(&o.Namespaces, "namespaces", []string{}, "A comma separated list of namespaces to dump.")
cmd.Flags().BoolVar(&o.AllNamespaces, "all-namespaces", false, "If true, dump all namespaces. If true, --namespaces is ignored.")
cmdutil.AddPodRunningTimeoutFlag(cmd, defaultPodLogsTimeout)
return cmd
}
@ -89,8 +102,7 @@ var (
kubectl cluster-info dump --namespaces default,kube-system --output-directory=/path/to/cluster-state`))
)
func setupOutputWriter(cmd *cobra.Command, defaultWriter io.Writer, filename string) io.Writer {
dir := cmdutil.GetFlagString(cmd, "output-directory")
func setupOutputWriter(dir string, defaultWriter io.Writer, filename string) io.Writer {
if len(dir) == 0 || dir == "-" {
return defaultWriter
}
@ -103,7 +115,7 @@ func setupOutputWriter(cmd *cobra.Command, defaultWriter io.Writer, filename str
return file
}
func (o *ClusterInfoDumpOptions) Complete() error {
func (o *ClusterInfoDumpOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
printer, err := o.PrintFlags.ToPrinter()
if err != nil {
return err
@ -113,32 +125,36 @@ func (o *ClusterInfoDumpOptions) Complete() error {
o.PrintFlags.OutputFormat = &jsonOutputFmt
o.PrintObj = printer.PrintObj
o.timeout, err = cmdutil.GetPodRunningTimeoutFlag(cmd)
if err != nil {
return err
}
o.clientset, err = f.ClientSet()
if err != nil {
return err
}
o.namespace, _, err = f.DefaultNamespace()
if err != nil {
return err
}
o.logsForObject = f.LogsForObject
return nil
}
func (o *ClusterInfoDumpOptions) Run(f cmdutil.Factory, cmd *cobra.Command) error {
timeout, err := cmdutil.GetPodRunningTimeoutFlag(cmd)
if err != nil {
return cmdutil.UsageErrorf(cmd, err.Error())
}
clientset, err := f.ClientSet()
func (o *ClusterInfoDumpOptions) Run() error {
nodes, err := o.clientset.Core().Nodes().List(metav1.ListOptions{})
if err != nil {
return err
}
nodes, err := clientset.Core().Nodes().List(metav1.ListOptions{})
if err != nil {
return err
}
if err := o.PrintObj(nodes, setupOutputWriter(cmd, o.Out, "nodes.json")); err != nil {
if err := o.PrintObj(nodes, setupOutputWriter(o.OutputDir, o.Out, "nodes.json")); err != nil {
return err
}
var namespaces []string
if cmdutil.GetFlagBool(cmd, "all-namespaces") {
namespaceList, err := clientset.Core().Namespaces().List(metav1.ListOptions{})
if o.AllNamespaces {
namespaceList, err := o.clientset.Core().Namespaces().List(metav1.ListOptions{})
if err != nil {
return err
}
@ -146,75 +162,70 @@ func (o *ClusterInfoDumpOptions) Run(f cmdutil.Factory, cmd *cobra.Command) erro
namespaces = append(namespaces, namespaceList.Items[ix].Name)
}
} else {
namespaces = cmdutil.GetFlagStringSlice(cmd, "namespaces")
if len(namespaces) == 0 {
cmdNamespace, _, err := f.DefaultNamespace()
if err != nil {
return err
}
if len(o.Namespaces) == 0 {
namespaces = []string{
metav1.NamespaceSystem,
cmdNamespace,
o.namespace,
}
}
}
for _, namespace := range namespaces {
// TODO: this is repetitive in the extreme. Use reflection or
// something to make this a for loop.
events, err := clientset.Core().Events(namespace).List(metav1.ListOptions{})
events, err := o.clientset.Core().Events(namespace).List(metav1.ListOptions{})
if err != nil {
return err
}
if err := o.PrintObj(events, setupOutputWriter(cmd, o.Out, path.Join(namespace, "events.json"))); err != nil {
if err := o.PrintObj(events, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "events.json"))); err != nil {
return err
}
rcs, err := clientset.Core().ReplicationControllers(namespace).List(metav1.ListOptions{})
rcs, err := o.clientset.Core().ReplicationControllers(namespace).List(metav1.ListOptions{})
if err != nil {
return err
}
if err := o.PrintObj(rcs, setupOutputWriter(cmd, o.Out, path.Join(namespace, "replication-controllers.json"))); err != nil {
if err := o.PrintObj(rcs, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "replication-controllers.json"))); err != nil {
return err
}
svcs, err := clientset.Core().Services(namespace).List(metav1.ListOptions{})
svcs, err := o.clientset.Core().Services(namespace).List(metav1.ListOptions{})
if err != nil {
return err
}
if err := o.PrintObj(svcs, setupOutputWriter(cmd, o.Out, path.Join(namespace, "services.json"))); err != nil {
if err := o.PrintObj(svcs, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "services.json"))); err != nil {
return err
}
sets, err := clientset.Extensions().DaemonSets(namespace).List(metav1.ListOptions{})
sets, err := o.clientset.Extensions().DaemonSets(namespace).List(metav1.ListOptions{})
if err != nil {
return err
}
if err := o.PrintObj(sets, setupOutputWriter(cmd, o.Out, path.Join(namespace, "daemonsets.json"))); err != nil {
if err := o.PrintObj(sets, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "daemonsets.json"))); err != nil {
return err
}
deps, err := clientset.Extensions().Deployments(namespace).List(metav1.ListOptions{})
deps, err := o.clientset.Extensions().Deployments(namespace).List(metav1.ListOptions{})
if err != nil {
return err
}
if err := o.PrintObj(deps, setupOutputWriter(cmd, o.Out, path.Join(namespace, "deployments.json"))); err != nil {
if err := o.PrintObj(deps, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "deployments.json"))); err != nil {
return err
}
rps, err := clientset.Extensions().ReplicaSets(namespace).List(metav1.ListOptions{})
rps, err := o.clientset.Extensions().ReplicaSets(namespace).List(metav1.ListOptions{})
if err != nil {
return err
}
if err := o.PrintObj(rps, setupOutputWriter(cmd, o.Out, path.Join(namespace, "replicasets.json"))); err != nil {
if err := o.PrintObj(rps, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "replicasets.json"))); err != nil {
return err
}
pods, err := clientset.Core().Pods(namespace).List(metav1.ListOptions{})
pods, err := o.clientset.Core().Pods(namespace).List(metav1.ListOptions{})
if err != nil {
return err
}
if err := o.PrintObj(pods, setupOutputWriter(cmd, o.Out, path.Join(namespace, "pods.json"))); err != nil {
if err := o.PrintObj(pods, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "pods.json"))); err != nil {
return err
}
@ -222,7 +233,7 @@ func (o *ClusterInfoDumpOptions) Run(f cmdutil.Factory, cmd *cobra.Command) erro
writer.Write([]byte(fmt.Sprintf("==== START logs for container %s of pod %s/%s ====\n", container.Name, pod.Namespace, pod.Name)))
defer writer.Write([]byte(fmt.Sprintf("==== END logs for container %s of pod %s/%s ====\n", container.Name, pod.Namespace, pod.Name)))
request, err := f.LogsForObject(pod, &api.PodLogOptions{Container: container.Name}, timeout)
request, err := o.logsForObject(pod, &api.PodLogOptions{Container: container.Name}, timeout)
if err != nil {
// Print error and return.
writer.Write([]byte(fmt.Sprintf("Create log request error: %s\n", err.Error())))
@ -241,19 +252,15 @@ func (o *ClusterInfoDumpOptions) Run(f cmdutil.Factory, cmd *cobra.Command) erro
for ix := range pods.Items {
pod := &pods.Items[ix]
containers := pod.Spec.Containers
writer := setupOutputWriter(cmd, o.Out, path.Join(namespace, pod.Name, "logs.txt"))
writer := setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, pod.Name, "logs.txt"))
for i := range containers {
printContainer(writer, containers[i], pod)
}
}
}
dir := cmdutil.GetFlagString(cmd, "output-directory")
if len(dir) == 0 {
dir = "standard output"
}
if dir != "-" {
fmt.Fprintf(o.Out, "Cluster info dumped to %s\n", dir)
if o.OutputDir != "-" {
fmt.Fprintf(o.Out, "Cluster info dumped to %s\n", o.OutputDir)
}
return nil
}

View File

@ -33,9 +33,7 @@ func TestSetupOutputWriterNoOp(t *testing.T) {
f := cmdtesting.NewTestFactory()
defer f.Cleanup()
cmd := NewCmdClusterInfoDump(f, genericclioptions.NewTestIOStreamsDiscard())
cmd.Flag("output-directory").Value.Set(test)
writer := setupOutputWriter(cmd, buf, "/some/file/that/should/be/ignored")
writer := setupOutputWriter(test, buf, "/some/file/that/should/be/ignored")
if writer != buf {
t.Errorf("expected: %v, saw: %v", buf, writer)
}
@ -55,9 +53,7 @@ func TestSetupOutputWriterFile(t *testing.T) {
f := cmdtesting.NewTestFactory()
defer f.Cleanup()
cmd := NewCmdClusterInfoDump(f, genericclioptions.NewTestIOStreamsDiscard())
cmd.Flag("output-directory").Value.Set(dir)
writer := setupOutputWriter(cmd, buf, file)
writer := setupOutputWriter(dir, buf, file)
if writer == buf {
t.Errorf("expected: %v, saw: %v", buf, writer)
}

View File

@ -308,7 +308,7 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
Message: "Advanced Commands:",
Commands: []*cobra.Command{
NewCmdApply("kubectl", f, ioStreams),
NewCmdPatch(f, out),
NewCmdPatch(f, ioStreams),
NewCmdReplace(f, out, err),
NewCmdConvert(f, ioStreams),
},
@ -349,8 +349,8 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
cmds.AddCommand(alpha)
cmds.AddCommand(cmdconfig.NewCmdConfig(f, clientcmd.NewDefaultPathOptions(), out, err))
cmds.AddCommand(NewCmdPlugin(f, in, out, err))
cmds.AddCommand(NewCmdVersion(f, out))
cmds.AddCommand(NewCmdApiVersions(f, out))
cmds.AddCommand(NewCmdVersion(f, ioStreams))
cmds.AddCommand(NewCmdApiVersions(f, ioStreams))
cmds.AddCommand(NewCmdApiResources(f, ioStreams))
cmds.AddCommand(NewCmdOptions(out))

View File

@ -68,6 +68,12 @@ type LabelOptions struct {
Recorder genericclioptions.Recorder
namespace string
enforceNamespace bool
includeUninitialized bool
builder *resource.Builder
unstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
// Common shared fields
genericclioptions.IOStreams
}
@ -125,13 +131,9 @@ func NewCmdLabel(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobr
Long: fmt.Sprintf(labelLong, validation.LabelValueMaxLength),
Example: labelExample,
Run: func(cmd *cobra.Command, args []string) {
if err := o.Complete(f, cmd, args); err != nil {
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, err.Error()))
}
if err := o.Validate(); err != nil {
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, err.Error()))
}
cmdutil.CheckErr(o.RunLabel(f, cmd))
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.RunLabel())
},
ValidArgs: validArgs,
ArgAliases: kubectl.ResourceAliases(validArgs),
@ -188,11 +190,19 @@ func (o *LabelOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
o.newLabels, o.removeLabels, err = parseLabels(labelArgs)
if o.list && len(o.outputFormat) > 0 {
return cmdutil.UsageErrorf(cmd, "--list and --output may not be specified together")
return fmt.Errorf("--list and --output may not be specified together")
}
o.namespace, o.enforceNamespace, err = f.DefaultNamespace()
if err != nil {
return err
}
o.includeUninitialized = cmdutil.ShouldIncludeUninitialized(cmd, false)
o.builder = f.NewBuilder()
o.unstructuredClientForMapping = f.UnstructuredClientForMapping
return nil
}
// Validate checks to the LabelOptions to see if there is sufficient information run the command.
func (o *LabelOptions) Validate() error {
@ -209,20 +219,14 @@ func (o *LabelOptions) Validate() error {
}
// RunLabel does the work
func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil {
return err
}
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
b := f.NewBuilder().
func (o *LabelOptions) RunLabel() error {
b := o.builder.
Unstructured().
LocalParam(o.local).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
IncludeUninitialized(includeUninitialized).
NamespaceParam(o.namespace).DefaultNamespace().
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
IncludeUninitialized(o.includeUninitialized).
Flatten()
if !o.local {
@ -294,7 +298,7 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
}
mapping := info.ResourceMapping()
client, err := f.UnstructuredClientForMapping(mapping)
client, err := o.unstructuredClientForMapping(mapping)
if err != nil {
return err
}

View File

@ -342,7 +342,7 @@ func TestLabelErrors(t *testing.T) {
err = opts.Validate()
}
if err == nil {
err = opts.RunLabel(tf, cmd)
err = opts.RunLabel()
}
if !testCase.errFn(err) {
t.Errorf("%s: unexpected error: %v", k, err)
@ -400,7 +400,7 @@ func TestLabelForResourceFromFile(t *testing.T) {
err = opts.Validate()
}
if err == nil {
err = opts.RunLabel(tf, cmd)
err = opts.RunLabel()
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
@ -434,7 +434,7 @@ func TestLabelLocal(t *testing.T) {
err = opts.Validate()
}
if err == nil {
err = opts.RunLabel(tf, cmd)
err = opts.RunLabel()
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
@ -491,7 +491,7 @@ func TestLabelMultipleObjects(t *testing.T) {
err = opts.Validate()
}
if err == nil {
err = opts.RunLabel(tf, cmd)
err = opts.RunLabel()
}
if err != nil {
t.Fatalf("unexpected error: %v", err)

View File

@ -18,7 +18,6 @@ package cmd
import (
"fmt"
"io"
"reflect"
"strings"
@ -26,6 +25,7 @@ import (
"github.com/golang/glog"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
@ -49,16 +49,25 @@ var patchTypes = map[string]types.PatchType{"json": types.JSONPatchType, "merge"
// referencing the cmd.Flags()
type PatchOptions struct {
resource.FilenameOptions
RecordFlags *genericclioptions.RecordFlags
PrintFlags *printers.PrintFlags
ToPrinter func(string) (printers.ResourcePrinterFunc, error)
Local bool
DryRun bool
Recorder genericclioptions.Recorder
OutputFormat string
Local bool
PatchType string
Patch string
namespace string
enforceNamespace bool
dryRun bool
outputFormat string
args []string
builder *resource.Builder
unstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
genericclioptions.IOStreams
}
var (
@ -86,16 +95,17 @@ var (
kubectl patch pod valid-pod --type='json' -p='[{"op": "replace", "path": "/spec/containers/0/image", "value":"new image"}]'`))
)
func NewPatchOptions() *PatchOptions {
func NewPatchOptions(ioStreams genericclioptions.IOStreams) *PatchOptions {
return &PatchOptions{
RecordFlags: genericclioptions.NewRecordFlags(),
Recorder: genericclioptions.NoopRecorder{},
PrintFlags: printers.NewPrintFlags("patched"),
IOStreams: ioStreams,
}
}
func NewCmdPatch(f cmdutil.Factory, out io.Writer) *cobra.Command {
o := NewPatchOptions()
func NewCmdPatch(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
o := NewPatchOptions(ioStreams)
validArgs := cmdutil.ValidArgList(f)
cmd := &cobra.Command{
@ -105,8 +115,9 @@ func NewCmdPatch(f cmdutil.Factory, out io.Writer) *cobra.Command {
Long: patchLong,
Example: patchExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd))
cmdutil.CheckErr(o.RunPatch(f, out, cmd, args))
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.RunPatch())
},
ValidArgs: validArgs,
ArgAliases: kubectl.ResourceAliases(validArgs),
@ -115,34 +126,30 @@ func NewCmdPatch(f cmdutil.Factory, out io.Writer) *cobra.Command {
o.RecordFlags.AddFlags(cmd)
o.PrintFlags.AddFlags(cmd)
cmd.Flags().StringP("patch", "p", "", "The patch to be applied to the resource JSON file.")
cmd.Flags().StringVarP(&o.Patch, "patch", "p", "", "The patch to be applied to the resource JSON file.")
cmd.MarkFlagRequired("patch")
cmd.Flags().String("type", "strategic", fmt.Sprintf("The type of patch being provided; one of %v", sets.StringKeySet(patchTypes).List()))
cmd.Flags().StringVar(&o.PatchType, "type", "strategic", fmt.Sprintf("The type of patch being provided; one of %v", sets.StringKeySet(patchTypes).List()))
cmdutil.AddDryRunFlag(cmd)
usage := "identifying the resource to update"
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "identifying the resource to update")
cmd.Flags().BoolVar(&o.Local, "local", o.Local, "If true, patch will operate on the content of the file, not the server-side resource.")
return cmd
}
func (o *PatchOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
func (o *PatchOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error
o.RecordFlags.Complete(f.Command(cmd, false))
o.Recorder, err = o.RecordFlags.ToRecorder()
if err != nil {
return err
}
o.OutputFormat = cmdutil.GetFlagString(cmd, "output")
o.DryRun = cmdutil.GetFlagBool(cmd, "dry-run")
o.outputFormat = cmdutil.GetFlagString(cmd, "output")
o.dryRun = cmdutil.GetFlagBool(cmd, "dry-run")
o.ToPrinter = func(operation string) (printers.ResourcePrinterFunc, error) {
o.PrintFlags.NamePrintFlags.Operation = operation
if o.DryRun {
if o.dryRun {
o.PrintFlags.Complete("%s (dry run)")
}
@ -153,46 +160,50 @@ func (o *PatchOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
return printer.PrintObj, nil
}
o.namespace, o.enforceNamespace, err = f.DefaultNamespace()
if err != nil {
return err
}
o.args = args
o.builder = f.NewBuilder()
o.unstructuredClientForMapping = f.UnstructuredClientForMapping
func (o *PatchOptions) RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
switch {
case o.Local && len(args) != 0:
return nil
}
func (o *PatchOptions) Validate() error {
if o.Local && len(o.args) != 0 {
return fmt.Errorf("cannot specify --local and server resources")
}
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil {
return err
if len(o.Patch) == 0 {
return fmt.Errorf("must specify -p to patch")
}
if len(o.PatchType) != 0 {
if _, ok := patchTypes[strings.ToLower(o.PatchType)]; !ok {
return fmt.Errorf("--type must be one of %v, not %q", sets.StringKeySet(patchTypes).List(), o.PatchType)
}
}
return nil
}
func (o *PatchOptions) RunPatch() error {
patchType := types.StrategicMergePatchType
patchTypeString := strings.ToLower(cmdutil.GetFlagString(cmd, "type"))
if len(patchTypeString) != 0 {
ok := false
patchType, ok = patchTypes[patchTypeString]
if !ok {
return cmdutil.UsageErrorf(cmd, "--type must be one of %v, not %q",
sets.StringKeySet(patchTypes).List(), patchTypeString)
}
if len(o.PatchType) != 0 {
patchType = patchTypes[strings.ToLower(o.PatchType)]
}
patch := cmdutil.GetFlagString(cmd, "patch")
if len(patch) == 0 {
return cmdutil.UsageErrorf(cmd, "Must specify -p to patch")
}
patchBytes, err := yaml.ToJSON([]byte(patch))
patchBytes, err := yaml.ToJSON([]byte(o.Patch))
if err != nil {
return fmt.Errorf("unable to parse %q: %v", patch, err)
return fmt.Errorf("unable to parse %q: %v", o.Patch, err)
}
r := f.NewBuilder().
r := o.builder.
Unstructured().
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
ResourceTypeOrNameArgs(false, args...).
NamespaceParam(o.namespace).DefaultNamespace().
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
ResourceTypeOrNameArgs(false, o.args...).
Flatten().
Do()
err = r.Err()
@ -207,12 +218,12 @@ func (o *PatchOptions) RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Com
}
name, namespace := info.Name, info.Namespace
mapping := info.ResourceMapping()
client, err := f.UnstructuredClientForMapping(mapping)
client, err := o.unstructuredClientForMapping(mapping)
if err != nil {
return err
}
if !o.Local && !o.DryRun {
if !o.Local && !o.dryRun {
helper := resource.NewHelper(client, mapping)
patchedObj, err := helper.Patch(namespace, name, patchType, patchBytes)
if err != nil {
@ -242,7 +253,7 @@ func (o *PatchOptions) RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Com
if err != nil {
return err
}
printer.PrintObj(info.Object, out)
printer.PrintObj(info.Object, o.Out)
// if object was not successfully patched, exit with error code 1
if !didPatch {
@ -285,7 +296,7 @@ func (o *PatchOptions) RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Com
if err != nil {
return err
}
return printer.PrintObj(info.Object, out)
return printer.PrintObj(info.Object, o.Out)
})
if err != nil {
return err

View File

@ -17,7 +17,6 @@ limitations under the License.
package cmd
import (
"bytes"
"net/http"
"strings"
"testing"
@ -25,6 +24,7 @@ import (
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
@ -56,9 +56,9 @@ func TestPatchObject(t *testing.T) {
}),
}
tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{})
stream, _, buf, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdPatch(tf, buf)
cmd := NewCmdPatch(tf, stream)
cmd.Flags().Set("namespace", "test")
cmd.Flags().Set("patch", `{"spec":{"type":"NodePort"}}`)
cmd.Flags().Set("output", "name")
@ -91,9 +91,9 @@ func TestPatchObjectFromFile(t *testing.T) {
}),
}
tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{})
stream, _, buf, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdPatch(tf, buf)
cmd := NewCmdPatch(tf, stream)
cmd.Flags().Set("namespace", "test")
cmd.Flags().Set("patch", `{"spec":{"type":"NodePort"}}`)
cmd.Flags().Set("output", "name")
@ -139,8 +139,8 @@ func TestPatchNoop(t *testing.T) {
patchObject.Annotations = map[string]string{}
}
patchObject.Annotations["foo"] = "bar"
buf := bytes.NewBuffer([]byte{})
cmd := NewCmdPatch(tf, buf)
stream, _, buf, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdPatch(tf, stream)
cmd.Flags().Set("namespace", "test")
cmd.Flags().Set("patch", `{"metadata":{"annotations":{"foo":"bar"}}}`)
cmd.Run(cmd, []string{"services", "frontend"})
@ -179,9 +179,9 @@ func TestPatchObjectFromFileOutput(t *testing.T) {
}),
}
tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{})
stream, _, buf, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdPatch(tf, buf)
cmd := NewCmdPatch(tf, stream)
cmd.Flags().Set("namespace", "test")
cmd.Flags().Set("patch", `{"spec":{"type":"NodePort"}}`)
cmd.Flags().Set("output", "yaml")

View File

@ -70,27 +70,23 @@ type ScaleOptions struct {
PrintFlags *printers.PrintFlags
PrintObj printers.ResourcePrinterFunc
BuilderArgs []string
Namespace string
EnforceNamespace bool
Builder *resource.Builder
ClientSet internalclientset.Interface
Scaler kubectl.Scaler
All bool
Selector string
CmdParent string
All bool
Replicas int
ResourceVersion string
CurrentReplicas int
Replicas int
Duration time.Duration
ClientForMapping func(*meta.RESTMapping) (resource.RESTClient, error)
Timeout time.Duration
Recorder genericclioptions.Recorder
builder *resource.Builder
namespace string
enforceNamespace bool
args []string
shortOutput bool
clientSet internalclientset.Interface
scaler kubectl.Scaler
unstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
parent string
genericclioptions.IOStreams
}
@ -99,17 +95,15 @@ func NewScaleOptions(ioStreams genericclioptions.IOStreams) *ScaleOptions {
return &ScaleOptions{
RecordFlags: genericclioptions.NewRecordFlags(),
PrintFlags: printers.NewPrintFlags("scaled"),
CurrentReplicas: -1,
Recorder: genericclioptions.NoopRecorder{},
IOStreams: ioStreams,
}
}
// NewCmdScale returns a cobra command with the appropriate configuration and flags to run scale
func NewCmdScale(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := NewScaleOptions(streams)
func NewCmdScale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
o := NewScaleOptions(ioStreams)
validArgs := []string{"deployment", "replicaset", "replicationcontroller", "statefulset"}
argAliases := kubectl.ResourceAliases(validArgs)
@ -122,7 +116,7 @@ func NewCmdScale(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.
Example: scaleExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
cmdutil.CheckErr(o.Validate(cmd))
cmdutil.CheckErr(o.RunScale())
},
ValidArgs: validArgs,
@ -138,71 +132,68 @@ func NewCmdScale(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.
cmd.Flags().IntVar(&o.CurrentReplicas, "current-replicas", o.CurrentReplicas, "Precondition for current size. Requires that the current size of the resource match this value in order to scale.")
cmd.Flags().IntVar(&o.Replicas, "replicas", o.Replicas, "The new desired number of replicas. Required.")
cmd.MarkFlagRequired("replicas")
cmd.Flags().DurationVar(&o.Duration, "timeout", o.Duration, "The length of time to wait before giving up on a scale operation, zero means don't wait. Any other values should contain a corresponding time unit (e.g. 1s, 2m, 3h).")
usage := "identifying the resource to set a new size"
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
cmd.Flags().DurationVar(&o.Timeout, "timeout", 0, "The length of time to wait before giving up on a scale operation, zero means don't wait. Any other values should contain a corresponding time unit (e.g. 1s, 2m, 3h).")
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "identifying the resource to set a new size")
return cmd
}
func (o *ScaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error
o.Namespace, o.EnforceNamespace, err = f.DefaultNamespace()
o.RecordFlags.Complete(f.Command(cmd, false))
o.Recorder, err = o.RecordFlags.ToRecorder()
if err != nil {
return err
}
o.CmdParent = cmd.Parent().Name()
o.Builder = f.NewBuilder()
o.ClientSet, err = f.ClientSet()
if err != nil {
return err
}
o.Scaler, err = f.Scaler()
if err != nil {
return err
}
o.BuilderArgs = args
o.ClientForMapping = f.UnstructuredClientForMapping
printer, err := o.PrintFlags.ToPrinter()
if err != nil {
return err
}
o.PrintObj = printer.PrintObj
o.RecordFlags.Complete(f.Command(cmd, false))
o.Recorder, err = o.RecordFlags.ToRecorder()
o.namespace, o.enforceNamespace, err = f.DefaultNamespace()
if err != nil {
return err
}
o.builder = f.NewBuilder()
o.args = args
o.shortOutput = cmdutil.GetFlagString(cmd, "output") == "name"
o.clientSet, err = f.ClientSet()
if err != nil {
return err
}
o.scaler, err = f.Scaler()
if err != nil {
return err
}
o.unstructuredClientForMapping = f.UnstructuredClientForMapping
o.parent = cmd.Parent().Name()
return nil
}
func (o *ScaleOptions) Validate(cmd *cobra.Command) error {
if err := cmdutil.ValidateOutputArgs(cmd); err != nil {
return err
}
if o.Replicas < 0 {
return fmt.Errorf("The --replicas=COUNT flag is required, and COUNT must be greater than or equal to 0")
}
return nil
}
// RunScale executes the scaling
func (o *ScaleOptions) RunScale() error {
if o.Replicas < 0 {
return fmt.Errorf("The --replicas=COUNT flag is required, and COUNT must be greater than or equal to 0")
}
r := o.Builder.
r := o.builder.
Unstructured().
ContinueOnError().
NamespaceParam(o.Namespace).DefaultNamespace().
FilenameParam(o.EnforceNamespace, &o.FilenameOptions).
ResourceTypeOrNameArgs(o.All, o.BuilderArgs...).
NamespaceParam(o.namespace).DefaultNamespace().
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
ResourceTypeOrNameArgs(o.All, o.args...).
Flatten().
LabelSelectorParam(o.Selector).
Do()
err := r.Err()
if resource.IsUsageError(err) {
return fmt.Errorf("%v", err)
}
if err != nil {
return err
}
@ -219,12 +210,11 @@ func (o *ScaleOptions) RunScale() error {
return fmt.Errorf("cannot use --resource-version with multiple resources")
}
currentSize := o.CurrentReplicas
precondition := &kubectl.ScalePrecondition{Size: currentSize, ResourceVersion: o.ResourceVersion}
precondition := &kubectl.ScalePrecondition{Size: o.CurrentReplicas, ResourceVersion: o.ResourceVersion}
retry := kubectl.NewRetryParams(kubectl.Interval, kubectl.Timeout)
var waitForReplicas *kubectl.RetryParams
if timeout := o.Duration; timeout != 0 {
if o.Timeout != 0 {
waitForReplicas = kubectl.NewRetryParams(kubectl.Interval, timeout)
}
@ -237,15 +227,15 @@ func (o *ScaleOptions) RunScale() error {
mapping := info.ResourceMapping()
if mapping.Resource == "jobs" {
// go down the legacy jobs path. This can be removed in 3.14 For now, contain it.
fmt.Fprintf(o.ErrOut, "%s scale job is DEPRECATED and will be removed in a future version.\n", o.CmdParent)
fmt.Fprintf(o.ErrOut, "%s scale job is DEPRECATED and will be removed in a future version.\n", o.parent)
if err := ScaleJob(info, o.ClientSet.Batch(), uint(o.Replicas), precondition, retry, waitForReplicas); err != nil {
if err := ScaleJob(info, o.clientSet.Batch(), uint(o.Replicas), precondition, retry, waitForReplicas); err != nil {
return err
}
} else {
gvk := mapping.GroupVersionKind.GroupVersion().WithResource(mapping.Resource)
if err := o.Scaler.Scale(info.Namespace, info.Name, uint(o.Replicas), precondition, retry, waitForReplicas, gvk.GroupResource()); err != nil {
if err := o.scaler.Scale(info.Namespace, info.Name, uint(o.Replicas), precondition, retry, waitForReplicas, gvk.GroupResource()); err != nil {
return err
}
}
@ -254,7 +244,7 @@ func (o *ScaleOptions) RunScale() error {
if mergePatch, err := o.Recorder.MakeRecordMergePatch(info.Object); err != nil {
glog.V(4).Infof("error recording current command: %v", err)
} else if len(mergePatch) > 0 {
client, err := o.ClientForMapping(mapping)
client, err := o.unstructuredClientForMapping(mapping)
if err != nil {
return err
}

View File

@ -24,19 +24,19 @@ import (
"strings"
"github.com/spf13/cobra"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/client-go/kubernetes"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
envutil "k8s.io/kubernetes/pkg/kubectl/cmd/util/env"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
)
var (
@ -94,32 +94,30 @@ var (
type EnvOptions struct {
PrintFlags *printers.PrintFlags
resource.FilenameOptions
EnvParams []string
EnvArgs []string
Resources []string
EnvParams []string
All bool
Resolve bool
List bool
Local bool
Overwrite bool
DryRun bool
ResourceVersion string
ContainerSelector string
Selector string
Output string
From string
Prefix string
PrintObj printers.ResourcePrinterFunc
Builder *resource.Builder
Infos []*resource.Info
UpdatePodSpecForObject func(obj runtime.Object, fn func(*v1.PodSpec) error) (bool, error)
envArgs []string
resources []string
output string
dryRun bool
builder func() *resource.Builder
updatePodSpecForObject func(obj runtime.Object, fn func(*v1.PodSpec) error) (bool, error)
namespace string
enforceNamespace bool
clientset *kubernetes.Clientset
genericclioptions.IOStreams
}
@ -139,7 +137,7 @@ func NewEnvOptions(streams genericclioptions.IOStreams) *EnvOptions {
// NewCmdEnv implements the OpenShift cli env command
func NewCmdEnv(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
options := NewEnvOptions(streams)
o := NewEnvOptions(streams)
cmd := &cobra.Command{
Use: "env RESOURCE/NAME KEY_1=VAL_1 ... KEY_N=VAL_N",
DisableFlagsInUseLine: true,
@ -147,24 +145,25 @@ func NewCmdEnv(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Co
Long: envLong,
Example: fmt.Sprintf(envExample),
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(f, cmd, args))
cmdutil.CheckErr(options.RunEnv(f))
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.RunEnv())
},
}
usage := "the resource to update the env"
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
cmd.Flags().StringVarP(&options.ContainerSelector, "containers", "c", options.ContainerSelector, "The names of containers in the selected pod templates to change - may use wildcards")
cmd.Flags().StringP("from", "", "", "The name of a resource from which to inject environment variables")
cmd.Flags().StringP("prefix", "", "", "Prefix to append to variable names")
cmd.Flags().StringArrayVarP(&options.EnvParams, "env", "e", options.EnvParams, "Specify a key-value pair for an environment variable to set into each container.")
cmd.Flags().BoolVar(&options.List, "list", options.List, "If true, display the environment and any changes in the standard format. this flag will removed when we have kubectl view env.")
cmd.Flags().BoolVar(&options.Resolve, "resolve", options.Resolve, "If true, show secret or configmap references when listing variables")
cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter on")
cmd.Flags().BoolVar(&options.Local, "local", options.Local, "If true, set env will NOT contact api-server but run locally.")
cmd.Flags().BoolVar(&options.All, "all", options.All, "If true, select all resources in the namespace of the specified resource types")
cmd.Flags().BoolVar(&options.Overwrite, "overwrite", options.Overwrite, "If true, allow environment to be overwritten, otherwise reject updates that overwrite existing environment.")
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
cmd.Flags().StringVarP(&o.ContainerSelector, "containers", "c", o.ContainerSelector, "The names of containers in the selected pod templates to change - may use wildcards")
cmd.Flags().StringVarP(&o.From, "from", "", "", "The name of a resource from which to inject environment variables")
cmd.Flags().StringVarP(&o.Prefix, "prefix", "", "", "Prefix to append to variable names")
cmd.Flags().StringArrayVarP(&o.EnvParams, "env", "e", o.EnvParams, "Specify a key-value pair for an environment variable to set into each container.")
cmd.Flags().BoolVar(&o.List, "list", o.List, "If true, display the environment and any changes in the standard format. this flag will removed when we have kubectl view env.")
cmd.Flags().BoolVar(&o.Resolve, "resolve", o.Resolve, "If true, show secret or configmap references when listing variables")
cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on")
cmd.Flags().BoolVar(&o.Local, "local", o.Local, "If true, set env will NOT contact api-server but run locally.")
cmd.Flags().BoolVar(&o.All, "all", o.All, "If true, select all resources in the namespace of the specified resource types")
cmd.Flags().BoolVar(&o.Overwrite, "overwrite", o.Overwrite, "If true, allow environment to be overwritten, otherwise reject updates that overwrite existing environment.")
options.PrintFlags.AddFlags(cmd)
o.PrintFlags.AddFlags(cmd)
cmdutil.AddDryRunFlag(cmd)
return cmd
@ -187,30 +186,17 @@ func (o *EnvOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri
if o.All && len(o.Selector) > 0 {
return fmt.Errorf("cannot set --all and --selector at the same time")
}
resources, envArgs, ok := envutil.SplitEnvironmentFromResources(args)
ok := false
o.resources, o.envArgs, ok = envutil.SplitEnvironmentFromResources(args)
if !ok {
return cmdutil.UsageErrorf(cmd, "all resources must be specified before environment changes: %s", strings.Join(args, " "))
}
if len(o.Filenames) == 0 && len(resources) < 1 {
return cmdutil.UsageErrorf(cmd, "one or more resources must be specified as <resource> <name> or <resource>/<name>")
return fmt.Errorf("all resources must be specified before environment changes: %s", strings.Join(args, " "))
}
o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
o.ContainerSelector = cmdutil.GetFlagString(cmd, "containers")
o.List = cmdutil.GetFlagBool(cmd, "list")
o.Resolve = cmdutil.GetFlagBool(cmd, "resolve")
o.Selector = cmdutil.GetFlagString(cmd, "selector")
o.All = cmdutil.GetFlagBool(cmd, "all")
o.Overwrite = cmdutil.GetFlagBool(cmd, "overwrite")
o.Output = cmdutil.GetFlagString(cmd, "output")
o.From = cmdutil.GetFlagString(cmd, "from")
o.Prefix = cmdutil.GetFlagString(cmd, "prefix")
o.DryRun = cmdutil.GetDryRunFlag(cmd)
o.updatePodSpecForObject = f.UpdatePodSpecForObject
o.output = cmdutil.GetFlagString(cmd, "output")
o.dryRun = cmdutil.GetDryRunFlag(cmd)
o.EnvArgs = envArgs
o.Resources = resources
if o.DryRun {
if o.dryRun {
// TODO(juanvallejo): This can be cleaned up even further by creating
// a PrintFlags struct that binds the --dry-run flag, and whose
// ToPrinter method returns a printer that understands how to print
@ -223,41 +209,43 @@ func (o *EnvOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri
}
o.PrintObj = printer.PrintObj
if o.List && len(o.Output) > 0 {
return cmdutil.UsageErrorf(cmd, "--list and --output may not be specified together")
o.clientset, err = f.KubernetesClientSet()
if err != nil {
return err
}
o.namespace, o.enforceNamespace, err = f.DefaultNamespace()
if err != nil {
return err
}
o.builder = f.NewBuilder
return nil
}
func (o *EnvOptions) Validate() error {
if len(o.Filenames) == 0 && len(o.resources) < 1 {
return fmt.Errorf("one or more resources must be specified as <resource> <name> or <resource>/<name>")
}
if o.List && len(o.output) > 0 {
return fmt.Errorf("--list and --output may not be specified together")
}
return nil
}
// RunEnv contains all the necessary functionality for the OpenShift cli env command
func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
var kubeClient *kubernetes.Clientset
if o.List {
client, err := f.KubernetesClientSet()
if err != nil {
return err
}
kubeClient = client
}
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil {
return err
}
env, remove, err := envutil.ParseEnv(append(o.EnvParams, o.EnvArgs...), o.In)
func (o *EnvOptions) RunEnv() error {
env, remove, err := envutil.ParseEnv(append(o.EnvParams, o.envArgs...), o.In)
if err != nil {
return err
}
if len(o.From) != 0 {
b := f.NewBuilder().
b := o.builder().
Internal(legacyscheme.Scheme).
LocalParam(o.Local).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
NamespaceParam(o.namespace).DefaultNamespace().
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
Flatten()
if !o.Local {
@ -320,27 +308,27 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
}
}
b := f.NewBuilder().
b := o.builder().
Internal(legacyscheme.Scheme).
LocalParam(o.Local).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
NamespaceParam(o.namespace).DefaultNamespace().
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
Flatten()
if !o.Local {
b.LabelSelectorParam(o.Selector).
ResourceTypeOrNameArgs(o.All, o.Resources...).
ResourceTypeOrNameArgs(o.All, o.resources...).
Latest()
}
o.Infos, err = b.Do().Infos()
infos, err := b.Do().Infos()
if err != nil {
return err
}
patches := CalculatePatches(o.Infos, cmdutil.InternalVersionJSONEncoder(), func(info *resource.Info) ([]byte, error) {
patches := CalculatePatches(infos, cmdutil.InternalVersionJSONEncoder(), func(info *resource.Info) ([]byte, error) {
info.Object = info.AsVersioned(legacyscheme.Scheme)
_, err := o.UpdatePodSpecForObject(info.Object, func(spec *v1.PodSpec) error {
_, err := o.updatePodSpecForObject(info.Object, func(spec *v1.PodSpec) error {
resolutionErrorsEncountered := false
containers, _ := selectContainers(spec.Containers, o.ContainerSelector)
if len(containers) == 0 {
@ -373,7 +361,7 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
continue
}
value, err := envutil.GetEnvVarRefValue(kubeClient, cmdNamespace, store, env.ValueFrom, info.Object, c)
value, err := envutil.GetEnvVarRefValue(o.clientset, o.namespace, store, env.ValueFrom, info.Object, c)
// Print the resolved value
if err == nil {
fmt.Fprintf(o.Out, "%s=%s\n", env.Name, value)
@ -429,7 +417,7 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
continue
}
if o.Local || o.DryRun {
if o.Local || o.dryRun {
if err := o.PrintObj(patch.Info.AsVersioned(legacyscheme.Scheme), o.Out); err != nil {
return err
}
@ -445,7 +433,7 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
// make sure arguments to set or replace environment variables are set
// before returning a successful message
if len(env) == 0 && len(o.EnvArgs) == 0 {
if len(env) == 0 && len(o.envArgs) == 0 {
return fmt.Errorf("at least one environment variable must be provided")
}

View File

@ -61,33 +61,28 @@ func TestSetEnvLocal(t *testing.T) {
}
tf.Namespace = "test"
tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}}
outputFormat := "name"
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdEnv(tf, streams)
cmd.SetOutput(buf)
cmd.Flags().Set("output", outputFormat)
cmd.Flags().Set("local", "true")
opts := EnvOptions{
PrintFlags: &printers.PrintFlags{
streams, _, buf, bufErr := genericclioptions.NewTestIOStreams()
opts := NewEnvOptions(streams)
opts.PrintFlags = &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags(""),
OutputFormat: &outputFormat,
},
FilenameOptions: resource.FilenameOptions{
Filenames: []string{"../../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}},
Local: true,
IOStreams: streams,
}
err := opts.Complete(tf, cmd, []string{"env=prod"})
if err == nil {
err = opts.RunEnv(tf)
opts.FilenameOptions = resource.FilenameOptions{
Filenames: []string{"../../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"},
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
opts.Local = true
err := opts.Complete(tf, NewCmdEnv(tf, streams), []string{"env=prod"})
assert.NoError(t, err)
err = opts.Validate()
assert.NoError(t, err)
err = opts.RunEnv()
assert.NoError(t, err)
if bufErr.Len() > 0 {
t.Errorf("unexpected error: %s", string(bufErr.String()))
}
if !strings.Contains(buf.String(), "replicationcontroller/cassandra") {
t.Errorf("did not set env: %s", buf.String())
@ -99,7 +94,6 @@ func TestSetMultiResourcesEnvLocal(t *testing.T) {
defer tf.Cleanup()
ns := legacyscheme.Codecs
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: ""},
NegotiatedSerializer: ns,
@ -112,33 +106,27 @@ func TestSetMultiResourcesEnvLocal(t *testing.T) {
tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}}
outputFormat := "name"
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdEnv(tf, streams)
cmd.SetOutput(buf)
cmd.Flags().Set("output", outputFormat)
cmd.Flags().Set("local", "true")
opts := EnvOptions{
PrintFlags: &printers.PrintFlags{
streams, _, buf, bufErr := genericclioptions.NewTestIOStreams()
opts := NewEnvOptions(streams)
opts.PrintFlags = &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags(""),
OutputFormat: &outputFormat,
},
FilenameOptions: resource.FilenameOptions{
Filenames: []string{"../../../../test/fixtures/pkg/kubectl/cmd/set/multi-resource-yaml.yaml"}},
Local: true,
IOStreams: streams,
}
err := opts.Complete(tf, cmd, []string{"env=prod"})
if err == nil {
err = opts.RunEnv(tf)
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
opts.FilenameOptions = resource.FilenameOptions{
Filenames: []string{"../../../../test/fixtures/pkg/kubectl/cmd/set/multi-resource-yaml.yaml"},
}
opts.Local = true
err := opts.Complete(tf, NewCmdEnv(tf, streams), []string{"env=prod"})
assert.NoError(t, err)
err = opts.Validate()
assert.NoError(t, err)
err = opts.RunEnv()
assert.NoError(t, err)
if bufErr.Len() > 0 {
t.Errorf("unexpected error: %s", string(bufErr.String()))
}
expectedOut := "replicationcontroller/first-rc\nreplicationcontroller/second-rc\n"
if buf.String() != expectedOut {
t.Errorf("expected out:\n%s\nbut got:\n%s", expectedOut, buf.String())
@ -472,6 +460,7 @@ func TestSetEnvRemote(t *testing.T) {
groupVersion := schema.GroupVersion{Group: input.apiGroup, Version: input.apiVersion}
testapi.Default = testapi.Groups[input.testAPIGroup]
tf := cmdtesting.NewTestFactory()
tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}}
defer tf.Cleanup()
codec := scheme.Codecs.CodecForVersions(scheme.Codecs.LegacyCodec(groupVersion), scheme.Codecs.UniversalDecoder(groupVersion), groupVersion, groupVersion)
@ -505,23 +494,18 @@ func TestSetEnvRemote(t *testing.T) {
}
outputFormat := "yaml"
streams := genericclioptions.NewTestIOStreamsDiscard()
cmd := NewCmdEnv(tf, streams)
cmd.Flags().Set("output", outputFormat)
opts := EnvOptions{
PrintFlags: &printers.PrintFlags{
opts := NewEnvOptions(streams)
opts.PrintFlags = &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags(""),
OutputFormat: &outputFormat,
},
Local: false,
IOStreams: streams,
}
err := opts.Complete(tf, cmd, input.args)
opts.Local = false
opts.IOStreams = streams
err := opts.Complete(tf, NewCmdEnv(tf, streams), input.args)
assert.NoError(t, err)
err = opts.RunEnv(tf)
err = opts.RunEnv()
assert.NoError(t, err)
})
}

View File

@ -73,6 +73,8 @@ type SubjectOptions struct {
Groups []string
ServiceAccounts []string
namespace string
PrintObj printers.ResourcePrinterFunc
genericclioptions.IOStreams
@ -87,8 +89,7 @@ func NewSubjectOptions(streams genericclioptions.IOStreams) *SubjectOptions {
}
func NewCmdSubject(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
options := NewSubjectOptions(streams)
o := NewSubjectOptions(streams)
cmd := &cobra.Command{
Use: "subject (-f FILENAME | TYPE NAME) [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run]",
DisableFlagsInUseLine: true,
@ -96,23 +97,22 @@ func NewCmdSubject(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobr
Long: subject_long,
Example: subject_example,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(f, cmd, args))
cmdutil.CheckErr(options.Validate())
cmdutil.CheckErr(options.Run(f, addSubjects))
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run(addSubjects))
},
}
options.PrintFlags.AddFlags(cmd)
o.PrintFlags.AddFlags(cmd)
usage := "the resource to update the subjects"
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
cmd.Flags().BoolVar(&options.All, "all", options.All, "Select all resources, including uninitialized ones, in the namespace of the specified resource types")
cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter on, not including uninitialized ones, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
cmd.Flags().BoolVar(&options.Local, "local", options.Local, "If true, set subject will NOT contact api-server but run locally.")
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "the resource to update the subjects")
cmd.Flags().BoolVar(&o.All, "all", o.All, "Select all resources, including uninitialized ones, in the namespace of the specified resource types")
cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on, not including uninitialized ones, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
cmd.Flags().BoolVar(&o.Local, "local", o.Local, "If true, set subject will NOT contact api-server but run locally.")
cmdutil.AddDryRunFlag(cmd)
cmd.Flags().StringArrayVar(&options.Users, "user", options.Users, "Usernames to bind to the role")
cmd.Flags().StringArrayVar(&options.Groups, "group", options.Groups, "Groups to bind to the role")
cmd.Flags().StringArrayVar(&options.ServiceAccounts, "serviceaccount", options.ServiceAccounts, "Service accounts to bind to the role")
cmd.Flags().StringArrayVar(&o.Users, "user", o.Users, "Usernames to bind to the role")
cmd.Flags().StringArrayVar(&o.Groups, "group", o.Groups, "Groups to bind to the role")
cmd.Flags().StringArrayVar(&o.ServiceAccounts, "serviceaccount", o.ServiceAccounts, "Service accounts to bind to the role")
cmdutil.AddIncludeUninitializedFlag(cmd)
return cmd
}
@ -130,7 +130,8 @@ func (o *SubjectOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
}
o.PrintObj = printer.PrintObj
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
var enforceNamespace bool
o.namespace, enforceNamespace, err = f.DefaultNamespace()
if err != nil {
return err
}
@ -140,7 +141,7 @@ func (o *SubjectOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
Internal(legacyscheme.Scheme).
LocalParam(o.Local).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
NamespaceParam(o.namespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
IncludeUninitialized(includeUninitialized).
Flatten()
@ -192,8 +193,7 @@ func (o *SubjectOptions) Validate() error {
return nil
}
func (o *SubjectOptions) Run(f cmdutil.Factory, fn updateSubjects) error {
var err error
func (o *SubjectOptions) Run(fn updateSubjects) error {
patches := CalculatePatches(o.Infos, cmdutil.InternalVersionJSONEncoder(), func(info *resource.Info) ([]byte, error) {
subjects := []rbac.Subject{}
for _, user := range sets.NewString(o.Users...).List() {
@ -217,10 +217,7 @@ func (o *SubjectOptions) Run(f cmdutil.Factory, fn updateSubjects) error {
namespace := tokens[0]
name := tokens[1]
if len(namespace) == 0 {
namespace, _, err = f.DefaultNamespace()
if err != nil {
return nil, err
}
namespace = o.namespace
}
subject := rbac.Subject{
Kind: rbac.ServiceAccountKind,

View File

@ -20,14 +20,15 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"github.com/ghodss/yaml"
"github.com/spf13/cobra"
apimachineryversion "k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/discovery"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/version"
)
@ -37,52 +38,67 @@ type Version struct {
ServerVersion *apimachineryversion.Info `json:"serverVersion,omitempty" yaml:"serverVersion,omitempty"`
}
// VersionOptions: describe the options available to users of the "kubectl
// version" command.
type VersionOptions struct {
clientOnly bool
short bool
output string
}
var (
versionExample = templates.Examples(i18n.T(`
# Print the client and server versions for the current context
kubectl version`))
)
func NewCmdVersion(f cmdutil.Factory, out io.Writer) *cobra.Command {
type VersionOptions struct {
ClientOnly bool
Short bool
Output string
discoveryClient discovery.CachedDiscoveryInterface
genericclioptions.IOStreams
}
func NewVersionOptions(ioStreams genericclioptions.IOStreams) *VersionOptions {
return &VersionOptions{
IOStreams: ioStreams,
}
}
func NewCmdVersion(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
o := NewVersionOptions(ioStreams)
cmd := &cobra.Command{
Use: "version",
Short: i18n.T("Print the client and server version information"),
Long: "Print the client and server version information for the current context",
Example: versionExample,
Run: func(cmd *cobra.Command, args []string) {
options := new(VersionOptions)
cmdutil.CheckErr(options.Complete(cmd))
cmdutil.CheckErr(options.Validate())
cmdutil.CheckErr(options.Run(f, out))
cmdutil.CheckErr(o.Complete(f, cmd))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run())
},
}
cmd.Flags().BoolP("client", "c", false, "Client version only (no server required).")
cmd.Flags().BoolP("short", "", false, "Print just the version number.")
cmd.Flags().StringP("output", "o", "", "One of 'yaml' or 'json'.")
cmd.Flags().BoolVarP(&o.ClientOnly, "client", "c", o.ClientOnly, "Client version only (no server required).")
cmd.Flags().BoolVarP(&o.Short, "short", "", o.Short, "Print just the version number.")
cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, "One of 'yaml' or 'json'.")
cmd.Flags().MarkShorthandDeprecated("client", "please use --client instead.")
return cmd
}
func retrieveServerVersion(f cmdutil.Factory) (*apimachineryversion.Info, error) {
discoveryClient, err := f.DiscoveryClient()
func (o *VersionOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
var err error
o.discoveryClient, err = f.DiscoveryClient()
if err != nil {
return nil, err
return err
}
return nil
}
// Always request fresh data from the server
discoveryClient.Invalidate()
return discoveryClient.ServerVersion()
func (o *VersionOptions) Validate() error {
if o.Output != "" && o.Output != "yaml" && o.Output != "json" {
return errors.New(`--output must be 'yaml' or 'json'`)
}
func (o *VersionOptions) Run(f cmdutil.Factory, out io.Writer) error {
return nil
}
func (o *VersionOptions) Run() error {
var (
serverVersion *apimachineryversion.Info
serverErr error
@ -92,22 +108,24 @@ func (o *VersionOptions) Run(f cmdutil.Factory, out io.Writer) error {
clientVersion := version.Get()
versionInfo.ClientVersion = &clientVersion
if !o.clientOnly {
serverVersion, serverErr = retrieveServerVersion(f)
if !o.ClientOnly {
// Always request fresh data from the server
o.discoveryClient.Invalidate()
serverVersion, serverErr = o.discoveryClient.ServerVersion()
versionInfo.ServerVersion = serverVersion
}
switch o.output {
switch o.Output {
case "":
if o.short {
fmt.Fprintf(out, "Client Version: %s\n", clientVersion.GitVersion)
if o.Short {
fmt.Fprintf(o.Out, "Client Version: %s\n", clientVersion.GitVersion)
if serverVersion != nil {
fmt.Fprintf(out, "Server Version: %s\n", serverVersion.GitVersion)
fmt.Fprintf(o.Out, "Server Version: %s\n", serverVersion.GitVersion)
}
} else {
fmt.Fprintf(out, "Client Version: %s\n", fmt.Sprintf("%#v", clientVersion))
fmt.Fprintf(o.Out, "Client Version: %s\n", fmt.Sprintf("%#v", clientVersion))
if serverVersion != nil {
fmt.Fprintf(out, "Server Version: %s\n", fmt.Sprintf("%#v", *serverVersion))
fmt.Fprintf(o.Out, "Server Version: %s\n", fmt.Sprintf("%#v", *serverVersion))
}
}
case "yaml":
@ -115,33 +133,18 @@ func (o *VersionOptions) Run(f cmdutil.Factory, out io.Writer) error {
if err != nil {
return err
}
fmt.Fprintln(out, string(marshalled))
fmt.Fprintln(o.Out, string(marshalled))
case "json":
marshalled, err := json.MarshalIndent(&versionInfo, "", " ")
if err != nil {
return err
}
fmt.Fprintln(out, string(marshalled))
fmt.Fprintln(o.Out, string(marshalled))
default:
// There is a bug in the program if we hit this case.
// However, we follow a policy of never panicking.
return fmt.Errorf("VersionOptions were not validated: --output=%q should have been rejected", o.output)
return fmt.Errorf("VersionOptions were not validated: --output=%q should have been rejected", o.Output)
}
return serverErr
}
func (o *VersionOptions) Complete(cmd *cobra.Command) error {
o.clientOnly = cmdutil.GetFlagBool(cmd, "client")
o.short = cmdutil.GetFlagBool(cmd, "short")
o.output = cmdutil.GetFlagString(cmd, "output")
return nil
}
func (o *VersionOptions) Validate() error {
if o.output != "" && o.output != "yaml" && o.output != "json" {
return errors.New(`--output must be 'yaml' or 'json'`)
}
return nil
}