Commit 999c8e21 authored by Mike Metral's avatar Mike Metral

allow kubectl subcmds to process multiple resources

- use resource.Visit() to recursively process resources, as well as, aggregate errors where possible
parent 9a871ed5
apiVersion: extensions/v1beta1
ind: Deployment
metadata:
name: nginx2-deployment
labels:
app: nginx2-deployment
spec:
replicas: 2
template:
metadata:
labels:
app: nginx2
spec:
containers:
- name: nginx
image: gcr.io/google-containers/nginx:1.7.9
ports:
- containerPort: 80
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx1-deployment
labels:
app: nginx1-deployment
spec:
replicas: 2
template:
metadata:
labels:
app: nginx1
spec:
containers:
- name: nginx
image: gcr.io/google-containers/nginx:1.7.9
ports:
- containerPort: 80
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx0-deployment
labels:
app: nginx0-deployment
spec:
replicas: 2
template:
metadata:
labels:
app: nginx0
spec:
containers:
- name: nginx
image: gcr.io/google-containers/nginx:1.7.9
ports:
- containerPort: 80
apiVersion: v1
kind: Pod
metadata:
name: busybox0
labels:
app: busybox0
status: replaced
spec:
containers:
- image: busybox
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always
apiVersion: v1
ind: Pod
metadata:
name: busybox2
labels:
app: busybox2
status: replaced
spec:
containers:
- image: busybox
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always
apiVersion: v1
kind: Pod
metadata:
name: busybox1
labels:
app: busybox1
status: replaced
spec:
containers:
- image: busybox
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always
apiVersion: v1
kind: Pod
metadata:
name: busybox0
labels:
app: busybox0
spec:
containers:
- image: busybox
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always
apiVersion: v1
ind: Pod
metadata:
name: busybox2
labels:
app: busybox2
spec:
containers:
- image: busybox
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always
apiVersion: v1
kind: Pod
metadata:
name: busybox1
labels:
app: busybox1
spec:
containers:
- image: busybox
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always
apiVersion: v1
kind: ReplicationController
metadata:
name: busybox0
labels:
app: busybox0
spec:
replicas: 1
selector:
app: busybox0
template:
metadata:
name: busybox0
labels:
app: busybox0
spec:
containers:
- image: busybox
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always
apiVersion: v1
ind: ReplicationController
metadata:
name: busybox2
labels:
app: busybox2
spec:
replicas: 1
selector:
app: busybox2
template:
metadata:
name: busybox2
labels:
app: busybox2
spec:
containers:
- image: busybox
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always
apiVersion: v1
kind: ReplicationController
metadata:
name: busybox1
labels:
app: busybox1
spec:
replicas: 1
selector:
app: busybox1
template:
metadata:
name: busybox1
labels:
app: busybox1
spec:
containers:
- image: busybox
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always
...@@ -23,7 +23,7 @@ import ( ...@@ -23,7 +23,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
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/util/errors" utilerrors "k8s.io/kubernetes/pkg/util/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
...@@ -97,18 +97,10 @@ func RunAutoscale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args [] ...@@ -97,18 +97,10 @@ func RunAutoscale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []
ResourceTypeOrNameArgs(false, args...). ResourceTypeOrNameArgs(false, args...).
Flatten(). Flatten().
Do() Do()
infos, err := r.Infos() err = r.Err()
if err != nil { if err != nil {
return err return err
} }
if len(infos) > 1 {
return fmt.Errorf("multiple resources provided: %v", args)
}
info := infos[0]
mapping := info.ResourceMapping()
if err := f.CanBeAutoscaled(mapping.GroupVersionKind.GroupKind()); err != nil {
return err
}
// 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")
...@@ -118,62 +110,84 @@ func RunAutoscale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args [] ...@@ -118,62 +110,84 @@ func RunAutoscale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []
return cmdutil.UsageError(cmd, fmt.Sprintf("generator %q not found.", generatorName)) return cmdutil.UsageError(cmd, fmt.Sprintf("generator %q not found.", generatorName))
} }
names := generator.ParamNames() names := generator.ParamNames()
params := kubectl.MakeParams(cmd, names)
name := info.Name
params["default-name"] = name
params["scaleRef-kind"] = mapping.GroupVersionKind.Kind count := 0
params["scaleRef-name"] = name err = r.Visit(func(info *resource.Info, err error) error {
params["scaleRef-apiVersion"] = mapping.GroupVersionKind.GroupVersion().String() if err != nil {
return err
}
if err = kubectl.ValidateParams(names, params); err != nil { mapping := info.ResourceMapping()
return err if err := f.CanBeAutoscaled(mapping.GroupVersionKind.GroupKind()); err != nil {
} return err
// Check for invalid flags used against the present generator. }
if err := kubectl.EnsureFlagsValid(cmd, generators, generatorName); err != nil {
return err
}
// Generate new object name := info.Name
object, err := generator.Generate(params) params := kubectl.MakeParams(cmd, names)
if err != nil { params["default-name"] = name
return err
}
resourceMapper := &resource.Mapper{ params["scaleRef-kind"] = mapping.GroupVersionKind.Kind
ObjectTyper: typer, params["scaleRef-name"] = name
RESTMapper: mapper, params["scaleRef-apiVersion"] = mapping.GroupVersionKind.GroupVersion().String()
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
Decoder: f.Decoder(true), if err = kubectl.ValidateParams(names, params); err != nil {
} return err
hpa, err := resourceMapper.InfoForObject(object, nil) }
if err != nil { // Check for invalid flags used against the present generator.
return err if err := kubectl.EnsureFlagsValid(cmd, generators, generatorName); err != nil {
}
if cmdutil.ShouldRecord(cmd, hpa) {
if err := cmdutil.RecordChangeCause(hpa.Object, f.Command()); err != nil {
return err return err
} }
object = hpa.Object
}
// TODO: extract this flag to a central location, when such a location exists.
if cmdutil.GetFlagBool(cmd, "dry-run") {
return f.PrintObject(cmd, mapper, object, out)
}
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), hpa, f.JSONEncoder()); err != nil { // Generate new object
return err object, err := generator.Generate(params)
} if err != nil {
return err
}
object, err = resource.NewHelper(hpa.Client, hpa.Mapping).Create(namespace, false, object) resourceMapper := &resource.Mapper{
ObjectTyper: typer,
RESTMapper: mapper,
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
Decoder: f.Decoder(true),
}
hpa, err := resourceMapper.InfoForObject(object, nil)
if err != nil {
return err
}
if cmdutil.ShouldRecord(cmd, hpa) {
if err := cmdutil.RecordChangeCause(hpa.Object, f.Command()); err != nil {
return err
}
object = hpa.Object
}
// TODO: extract this flag to a central location, when such a location exists.
if cmdutil.GetFlagBool(cmd, "dry-run") {
return f.PrintObject(cmd, mapper, object, out)
}
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), hpa, f.JSONEncoder()); err != nil {
return err
}
object, err = resource.NewHelper(hpa.Client, hpa.Mapping).Create(namespace, false, object)
if err != nil {
return err
}
count++
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
return f.PrintObject(cmd, mapper, object, out)
}
cmdutil.PrintSuccess(mapper, false, out, info.Mapping.Resource, info.Name, "autoscaled")
return nil
})
if err != nil { if err != nil {
return err return err
} }
if count == 0 {
if len(cmdutil.GetFlagString(cmd, "output")) > 0 { return fmt.Errorf("no objects passed to autoscale")
return f.PrintObject(cmd, mapper, object, out)
} }
cmdutil.PrintSuccess(mapper, false, out, info.Mapping.Resource, info.Name, "autoscaled")
return nil return nil
} }
...@@ -186,5 +200,5 @@ func validateFlags(cmd *cobra.Command) error { ...@@ -186,5 +200,5 @@ func validateFlags(cmd *cobra.Command) error {
if cpu > 100 { if cpu > 100 {
errs = append(errs, fmt.Errorf("CPU utilization (%%) cannot exceed 100")) errs = append(errs, fmt.Errorf("CPU utilization (%%) cannot exceed 100"))
} }
return errors.NewAggregate(errs) return utilerrors.NewAggregate(errs)
} }
...@@ -154,15 +154,32 @@ func (o *ConvertOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra. ...@@ -154,15 +154,32 @@ func (o *ConvertOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra.
// RunConvert implements the generic Convert command // RunConvert implements the generic Convert command
func (o *ConvertOptions) RunConvert() error { func (o *ConvertOptions) RunConvert() error {
infos, err := o.builder.Do().Infos() r := o.builder.Do()
err := r.Err()
if err != nil { if err != nil {
return err return err
} }
objects, err := resource.AsVersionedObject(infos, false, o.outputVersion.String(), o.encoder) count := 0
err = r.Visit(func(info *resource.Info, err error) error {
if err != nil {
return err
}
infos := []*resource.Info{info}
objects, err := resource.AsVersionedObject(infos, false, o.outputVersion.String(), o.encoder)
if err != nil {
return err
}
count++
return o.printer.PrintObj(objects, o.out)
})
if err != nil { if err != nil {
return err return err
} }
if count == 0 {
return o.printer.PrintObj(objects, o.out) return fmt.Errorf("no objects passed to convert")
}
return nil
} }
...@@ -140,20 +140,7 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str ...@@ -140,20 +140,7 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
ResourceTypeOrNameArgs(false, args...). ResourceTypeOrNameArgs(false, args...).
Flatten(). Flatten().
Do() Do()
infos, err := r.Infos() err = r.Err()
if err != nil {
return err
}
if len(infos) > 1 {
return fmt.Errorf("multiple resources provided: %v", args)
}
info := infos[0]
mapping := info.ResourceMapping()
if err := f.CanBeExposed(mapping.GroupVersionKind.GroupKind()); err != nil {
return err
}
// Get the input object
inputObject, err := r.Object()
if err != nil { if err != nil {
return err return err
} }
...@@ -166,101 +153,118 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str ...@@ -166,101 +153,118 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
return cmdutil.UsageError(cmd, fmt.Sprintf("generator %q not found.", generatorName)) return cmdutil.UsageError(cmd, fmt.Sprintf("generator %q not found.", generatorName))
} }
names := generator.ParamNames() names := generator.ParamNames()
params := kubectl.MakeParams(cmd, names)
name := info.Name
if len(name) > validation.DNS952LabelMaxLength {
name = name[:validation.DNS952LabelMaxLength]
}
params["default-name"] = name
// For objects that need a pod selector, derive it from the exposed object in case a user err = r.Visit(func(info *resource.Info, err error) error {
// didn't explicitly specify one via --selector
if s, found := params["selector"]; found && kubectl.IsZero(s) {
s, err := f.MapBasedSelectorForObject(inputObject)
if err != nil { if err != nil {
return cmdutil.UsageError(cmd, fmt.Sprintf("couldn't retrieve selectors via --selector flag or introspection: %s", err)) return err
} }
params["selector"] = s
}
// For objects that need a port, derive it from the exposed object in case a user mapping := info.ResourceMapping()
// didn't explicitly specify one via --port if err := f.CanBeExposed(mapping.GroupVersionKind.GroupKind()); err != nil {
if port, found := params["port"]; found && kubectl.IsZero(port) { return err
ports, err := f.PortsForObject(inputObject)
if err != nil {
return cmdutil.UsageError(cmd, fmt.Sprintf("couldn't find port via --port flag or introspection: %s", err))
} }
switch len(ports) {
case 0: params := kubectl.MakeParams(cmd, names)
return cmdutil.UsageError(cmd, "couldn't find port via --port flag or introspection") name := info.Name
case 1: if len(name) > validation.DNS952LabelMaxLength {
params["port"] = ports[0] name = name[:validation.DNS952LabelMaxLength]
default:
params["ports"] = strings.Join(ports, ",")
} }
} params["default-name"] = name
if kubectl.IsZero(params["labels"]) {
labels, err := f.LabelsForObject(inputObject) // For objects that need a pod selector, derive it from the exposed object in case a user
// didn't explicitly specify one via --selector
if s, found := params["selector"]; found && kubectl.IsZero(s) {
s, err := f.MapBasedSelectorForObject(info.Object)
if err != nil {
return cmdutil.UsageError(cmd, fmt.Sprintf("couldn't retrieve selectors via --selector flag or introspection: %s", err))
}
params["selector"] = s
}
// For objects that need a port, derive it from the exposed object in case a user
// didn't explicitly specify one via --port
if port, found := params["port"]; found && kubectl.IsZero(port) {
ports, err := f.PortsForObject(info.Object)
if err != nil {
return cmdutil.UsageError(cmd, fmt.Sprintf("couldn't find port via --port flag or introspection: %s", err))
}
switch len(ports) {
case 0:
return cmdutil.UsageError(cmd, "couldn't find port via --port flag or introspection")
case 1:
params["port"] = ports[0]
default:
params["ports"] = strings.Join(ports, ",")
}
}
if kubectl.IsZero(params["labels"]) {
labels, err := f.LabelsForObject(info.Object)
if err != nil {
return err
}
params["labels"] = kubectl.MakeLabels(labels)
}
if err = kubectl.ValidateParams(names, params); err != nil {
return err
}
// Check for invalid flags used against the present generator.
if err := kubectl.EnsureFlagsValid(cmd, generators, generatorName); err != nil {
return err
}
// Generate new object
object, err := generator.Generate(params)
if err != nil { if err != nil {
return err return err
} }
params["labels"] = kubectl.MakeLabels(labels)
}
if err = kubectl.ValidateParams(names, params); err != nil {
return err
}
// Check for invalid flags used against the present generator.
if err := kubectl.EnsureFlagsValid(cmd, generators, generatorName); err != nil {
return err
}
// Generate new object if inline := cmdutil.GetFlagString(cmd, "overrides"); len(inline) > 0 {
object, err := generator.Generate(params) codec := runtime.NewCodec(f.JSONEncoder(), f.Decoder(true))
if err != nil { object, err = cmdutil.Merge(codec, object, inline, mapping.GroupVersionKind.Kind)
return err if err != nil {
} return err
}
}
if inline := cmdutil.GetFlagString(cmd, "overrides"); len(inline) > 0 { resourceMapper := &resource.Mapper{
codec := runtime.NewCodec(f.JSONEncoder(), f.Decoder(true)) ObjectTyper: typer,
object, err = cmdutil.Merge(codec, object, inline, mapping.GroupVersionKind.Kind) RESTMapper: mapper,
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
Decoder: f.Decoder(true),
}
info, err = resourceMapper.InfoForObject(object, nil)
if err != nil { if err != nil {
return err return err
} }
} if cmdutil.ShouldRecord(cmd, info) {
if err := cmdutil.RecordChangeCause(object, f.Command()); err != nil {
return err
}
}
info.Refresh(object, true)
// TODO: extract this flag to a central location, when such a location exists.
if cmdutil.GetFlagBool(cmd, "dry-run") {
return f.PrintObject(cmd, mapper, object, out)
}
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
return err
}
resourceMapper := &resource.Mapper{ // Serialize the object with the annotation applied.
ObjectTyper: typer, object, err = resource.NewHelper(info.Client, info.Mapping).Create(namespace, false, object)
RESTMapper: mapper, if err != nil {
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
Decoder: f.Decoder(true),
}
info, err = resourceMapper.InfoForObject(object, nil)
if err != nil {
return err
}
if cmdutil.ShouldRecord(cmd, info) {
if err := cmdutil.RecordChangeCause(object, f.Command()); err != nil {
return err return err
} }
}
info.Refresh(object, true)
// TODO: extract this flag to a central location, when such a location exists.
if cmdutil.GetFlagBool(cmd, "dry-run") {
return f.PrintObject(cmd, mapper, object, out)
}
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
return err
}
// Serialize the object with the annotation applied. if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
object, err = resource.NewHelper(info.Client, info.Mapping).Create(namespace, false, object) return f.PrintObject(cmd, mapper, object, out)
}
cmdutil.PrintSuccess(mapper, false, out, info.Mapping.Resource, info.Name, "exposed")
return nil
})
if err != nil { if err != nil {
return err return err
} }
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
return f.PrintObject(cmd, mapper, object, out)
}
cmdutil.PrintSuccess(mapper, false, out, info.Mapping.Resource, info.Name, "exposed")
return nil return nil
} }
...@@ -26,6 +26,7 @@ import ( ...@@ -26,6 +26,7 @@ import (
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/runtime" "k8s.io/kubernetes/pkg/runtime"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
"k8s.io/kubernetes/pkg/watch" "k8s.io/kubernetes/pkg/watch"
) )
...@@ -197,32 +198,48 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string ...@@ -197,32 +198,48 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
return nil return nil
} }
b := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)). r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces). NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
FilenameParam(enforceNamespace, options.Recursive, options.Filenames...). FilenameParam(enforceNamespace, options.Recursive, options.Filenames...).
SelectorParam(selector). SelectorParam(selector).
ExportParam(export). ExportParam(export).
ResourceTypeOrNameArgs(true, args...). ResourceTypeOrNameArgs(true, args...).
ContinueOnError(). ContinueOnError().
Latest() Latest().
Flatten().
Do()
err = r.Err()
if err != nil {
return err
}
printer, generic, err := cmdutil.PrinterForCommand(cmd) printer, generic, err := cmdutil.PrinterForCommand(cmd)
if err != nil { if err != nil {
return err return err
} }
if generic { infos := []*resource.Info{}
clientConfig, err := f.ClientConfig() allErrs := []error{}
err = r.Visit(func(info *resource.Info, err error) error {
if err != nil { if err != nil {
return err return err
} }
infos = append(infos, info)
return nil
})
if err != nil {
allErrs = append(allErrs, err)
}
singular := false if generic {
r := b.Flatten().Do() clientConfig, err := f.ClientConfig()
infos, err := r.IntoSingular(&singular).Infos()
if err != nil { if err != nil {
return err return err
} }
singular := false
r.IntoSingular(&singular)
// the outermost object will be converted to the output-version, but inner // the outermost object will be converted to the output-version, but inner
// objects can use their mappings // objects can use their mappings
version, err := cmdutil.OutputVersion(cmd, clientConfig.GroupVersion) version, err := cmdutil.OutputVersion(cmd, clientConfig.GroupVersion)
...@@ -237,10 +254,6 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string ...@@ -237,10 +254,6 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
return printer.PrintObj(obj, out) return printer.PrintObj(obj, out)
} }
infos, err := b.Flatten().Do().Infos()
if err != nil {
return err
}
objs := make([]runtime.Object, len(infos)) objs := make([]runtime.Object, len(infos))
for ix := range infos { for ix := range infos {
objs[ix] = infos[ix].Object objs[ix] = infos[ix].Object
...@@ -262,7 +275,8 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string ...@@ -262,7 +275,8 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
for ix := range infos { for ix := range infos {
objs[ix], err = infos[ix].Mapping.ConvertToVersion(infos[ix].Object, version.String()) objs[ix], err = infos[ix].Mapping.ConvertToVersion(infos[ix].Object, version.String())
if err != nil { if err != nil {
return err allErrs = append(allErrs, err)
continue
} }
} }
...@@ -291,19 +305,21 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string ...@@ -291,19 +305,21 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
if printer == nil || lastMapping == nil || mapping == nil || mapping.Resource != lastMapping.Resource { if printer == nil || lastMapping == nil || mapping == nil || mapping.Resource != lastMapping.Resource {
printer, err = f.PrinterForMapping(cmd, mapping, allNamespaces) printer, err = f.PrinterForMapping(cmd, mapping, allNamespaces)
if err != nil { if err != nil {
return err allErrs = append(allErrs, err)
continue
} }
lastMapping = mapping lastMapping = mapping
} }
if _, found := printer.(*kubectl.HumanReadablePrinter); found { if _, found := printer.(*kubectl.HumanReadablePrinter); found {
if err := printer.PrintObj(original, w); err != nil { if err := printer.PrintObj(original, w); err != nil {
return err allErrs = append(allErrs, err)
} }
continue continue
} }
if err := printer.PrintObj(original, w); err != nil { if err := printer.PrintObj(original, w); err != nil {
return err allErrs = append(allErrs, err)
continue
} }
} }
return nil return utilerrors.NewAggregate(allErrs)
} }
...@@ -137,35 +137,41 @@ func RunPatch(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri ...@@ -137,35 +137,41 @@ func RunPatch(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
return err return err
} }
infos, err := r.Infos() count := 0
if err != nil { err = r.Visit(func(info *resource.Info, err error) error {
return err if err != nil {
} return err
if len(infos) > 1 { }
return fmt.Errorf("multiple resources provided") name, namespace := info.Name, info.Namespace
} mapping := info.ResourceMapping()
info := infos[0] client, err := f.ClientForMapping(mapping)
name, namespace := info.Name, info.Namespace if err != nil {
mapping := info.ResourceMapping() return err
client, err := f.ClientForMapping(mapping) }
if err != nil {
return err
}
helper := resource.NewHelper(client, mapping) helper := resource.NewHelper(client, mapping)
patchedObject, err := helper.Patch(namespace, name, patchType, patchBytes) patchedObject, err := helper.Patch(namespace, name, patchType, patchBytes)
if err != nil {
return err
}
if cmdutil.ShouldRecord(cmd, info) {
if err := cmdutil.RecordChangeCause(patchedObject, f.Command()); err == nil {
// don't return an error on failure. The patch itself succeeded, its only the hint for that change that failed
// don't bother checking for failures of this replace, because a failure to indicate the hint doesn't fail the command
// also, don't force the replacement. If the replacement fails on a resourceVersion conflict, then it means this
// record hint is likely to be invalid anyway, so avoid the bad hint
resource.NewHelper(client, mapping).Replace(namespace, name, false, patchedObject)
}
}
count++
cmdutil.PrintSuccess(mapper, shortOutput, out, "", name, "patched")
return nil
})
if err != nil { if err != nil {
return err return err
} }
if cmdutil.ShouldRecord(cmd, info) { if count == 0 {
if err := cmdutil.RecordChangeCause(patchedObject, f.Command()); err == nil { return fmt.Errorf("no objects passed to patch")
// don't return an error on failure. The patch itself succeeded, its only the hint for that change that failed
// don't bother checking for failures of this replace, because a failure to indicate the hint doesn't fail the command
// also, don't force the replacement. If the replacement fails on a resourceVersion conflict, then it means this
// record hint is likely to be invalid anyway, so avoid the bad hint
resource.NewHelper(client, mapping).Replace(namespace, name, false, patchedObject)
}
} }
cmdutil.PrintSuccess(mapper, shortOutput, out, "", name, "patched")
return nil return nil
} }
...@@ -27,7 +27,6 @@ import ( ...@@ -27,7 +27,6 @@ import (
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
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"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
) )
// ScaleOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of // ScaleOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
...@@ -122,43 +121,47 @@ func RunScale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri ...@@ -122,43 +121,47 @@ func RunScale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
return err return err
} }
infos, err := r.Infos() infos := []*resource.Info{}
if err != nil { err = r.Visit(func(info *resource.Info, err error) error {
return err if err == nil {
} infos = append(infos, info)
info := infos[0] }
mapping := info.ResourceMapping() return nil
scaler, err := f.Scaler(mapping) })
if err != nil {
return err
}
resourceVersion := cmdutil.GetFlagString(cmd, "resource-version") resourceVersion := cmdutil.GetFlagString(cmd, "resource-version")
if len(resourceVersion) != 0 && len(infos) > 1 { if len(resourceVersion) != 0 && len(infos) > 1 {
return fmt.Errorf("cannot use --resource-version with multiple resources") return fmt.Errorf("cannot use --resource-version with multiple resources")
} }
currentSize := cmdutil.GetFlagInt(cmd, "current-replicas")
if currentSize != -1 && len(infos) > 1 {
return fmt.Errorf("cannot use --current-replicas with multiple resources")
}
precondition := &kubectl.ScalePrecondition{Size: currentSize, ResourceVersion: resourceVersion}
retry := kubectl.NewRetryParams(kubectl.Interval, kubectl.Timeout)
var waitForReplicas *kubectl.RetryParams
if timeout := cmdutil.GetFlagDuration(cmd, "timeout"); timeout != 0 {
waitForReplicas = kubectl.NewRetryParams(kubectl.Interval, timeout)
}
errs := []error{} counter := 0
for _, info := range infos { err = r.Visit(func(info *resource.Info, err error) error {
if err != nil {
return err
}
mapping := info.ResourceMapping()
scaler, err := f.Scaler(mapping)
if err != nil {
return err
}
currentSize := cmdutil.GetFlagInt(cmd, "current-replicas")
precondition := &kubectl.ScalePrecondition{Size: currentSize, ResourceVersion: resourceVersion}
retry := kubectl.NewRetryParams(kubectl.Interval, kubectl.Timeout)
var waitForReplicas *kubectl.RetryParams
if timeout := cmdutil.GetFlagDuration(cmd, "timeout"); timeout != 0 {
waitForReplicas = kubectl.NewRetryParams(kubectl.Interval, timeout)
}
if err := scaler.Scale(info.Namespace, info.Name, uint(count), precondition, retry, waitForReplicas); err != nil { if err := scaler.Scale(info.Namespace, info.Name, uint(count), precondition, retry, waitForReplicas); err != nil {
errs = append(errs, err) return err
continue
} }
if cmdutil.ShouldRecord(cmd, info) { if cmdutil.ShouldRecord(cmd, info) {
patchBytes, err := cmdutil.ChangeResourcePatch(info, f.Command()) patchBytes, err := cmdutil.ChangeResourcePatch(info, f.Command())
if err != nil { if err != nil {
errs = append(errs, err) return err
continue
} }
mapping := info.ResourceMapping() mapping := info.ResourceMapping()
client, err := f.ClientForMapping(mapping) client, err := f.ClientForMapping(mapping)
...@@ -168,12 +171,18 @@ func RunScale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri ...@@ -168,12 +171,18 @@ func RunScale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
helper := resource.NewHelper(client, mapping) helper := resource.NewHelper(client, mapping)
_, err = helper.Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patchBytes) _, err = helper.Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patchBytes)
if err != nil { if err != nil {
errs = append(errs, err) return err
continue
} }
} }
counter++
cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "scaled") cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "scaled")
return nil
})
if err != nil {
return err
} }
if counter == 0 {
return utilerrors.NewAggregate(errs) return fmt.Errorf("no objects passed to scale")
}
return nil
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment