Adds support for multiple resources to kubectl

You can specify multiple resources by name when using the delete, get
and stop commands.
This commit is contained in:
Karl Beecher
2015-02-19 15:17:23 +01:00
parent 0e1c0b26dc
commit ecbb91cc08
2 changed files with 66 additions and 31 deletions

View File

@@ -48,7 +48,7 @@ type Builder struct {
resources []string
namespace string
name string
names []string
defaultNamespace bool
requireNamespace bool
@@ -217,22 +217,25 @@ func (b *Builder) SelectAllParam(selectAll bool) *Builder {
return b
}
// ResourceTypeOrNameArgs indicates that the builder should accept one or two arguments
// of the form `(<type1>[,<type2>,...]|<type> <name>)`. When one argument is received, the types
// provided will be retrieved from the server (and be comma delimited). When two arguments are
// received, they must be a single type and name. If more than two arguments are provided an
// error is set. The allowEmptySelector permits to select all the resources (via Everything func).
// ResourceTypeOrNameArgs indicates that the builder should accept arguments
// of the form `(<type1>[,<type2>,...]|<type> <name1>[,<name2>,...])`. When one argument is
// received, the types provided will be retrieved from the server (and be comma delimited).
// When two or more arguments are received, they must be a single type and resource name(s).
// The allowEmptySelector permits to select all the resources (via Everything func).
func (b *Builder) ResourceTypeOrNameArgs(allowEmptySelector bool, args ...string) *Builder {
switch len(args) {
case 2:
b.name = args[1]
switch {
case len(args) > 2:
b.names = append(b.names, args[1:]...)
b.ResourceTypes(SplitResourceArgument(args[0])...)
case 1:
case len(args) == 2:
b.names = append(b.names, args[1])
b.ResourceTypes(SplitResourceArgument(args[0])...)
case len(args) == 1:
b.ResourceTypes(SplitResourceArgument(args[0])...)
if b.selector == nil && allowEmptySelector {
b.selector = labels.Everything()
}
case 0:
case len(args) == 0:
default:
b.errs = append(b.errs, fmt.Errorf("when passing arguments, must be resource or resource and name"))
}
@@ -244,7 +247,7 @@ func (b *Builder) ResourceTypeOrNameArgs(allowEmptySelector bool, args ...string
func (b *Builder) ResourceTypeAndNameArgs(args ...string) *Builder {
switch len(args) {
case 2:
b.name = args[1]
b.names = append(b.names, args[1])
b.ResourceTypes(SplitResourceArgument(args[0])...)
case 0:
default:
@@ -312,7 +315,7 @@ func (b *Builder) visitorResult() *Result {
// visit selectors
if b.selector != nil {
if len(b.name) != 0 {
if len(b.names) != 0 {
return &Result{err: fmt.Errorf("name cannot be provided when a selector is specified")}
}
if len(b.resources) == 0 {
@@ -349,38 +352,49 @@ func (b *Builder) visitorResult() *Result {
return &Result{visitor: VisitorList(visitors), sources: visitors}
}
// visit single item specified by name
if len(b.name) != 0 {
// visit items specified by name
if len(b.names) != 0 {
isSingular := len(b.names) == 1
if len(b.paths) != 0 {
return &Result{singular: true, err: fmt.Errorf("when paths, URLs, or stdin is provided as input, you may not specify a resource by arguments as well")}
return &Result{singular: isSingular, err: fmt.Errorf("when paths, URLs, or stdin is provided as input, you may not specify a resource by arguments as well")}
}
if len(b.resources) == 0 {
return &Result{singular: true, err: fmt.Errorf("you must provide a resource and a resource name together")}
return &Result{singular: isSingular, err: fmt.Errorf("you must provide a resource and a resource name together")}
}
if len(b.resources) > 1 {
return &Result{singular: true, err: fmt.Errorf("you must specify only one resource")}
return &Result{singular: isSingular, err: fmt.Errorf("you must specify only one resource")}
}
mappings, err := b.resourceMappings()
if err != nil {
return &Result{singular: true, err: err}
return &Result{singular: isSingular, err: err}
}
mapping := mappings[0]
if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
b.namespace = ""
} else {
if len(b.namespace) == 0 {
return &Result{singular: true, err: fmt.Errorf("namespace may not be empty when retrieving a resource by name")}
}
}
client, err := b.mapper.ClientForMapping(mapping)
if err != nil {
return &Result{singular: true, err: err}
return &Result{err: err}
}
info := NewInfo(client, mappings[0], b.namespace, b.name)
if err := info.Get(); err != nil {
return &Result{singular: true, err: err}
selectorNamespace := b.namespace
if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
selectorNamespace = ""
} else {
if len(b.namespace) == 0 {
return &Result{singular: isSingular, err: fmt.Errorf("namespace may not be empty when retrieving a resource by name")}
}
}
return &Result{singular: true, visitor: info, sources: []Visitor{info}}
visitors := []Visitor{}
for _, name := range b.names {
info := NewInfo(client, mapping, selectorNamespace, name)
if err := info.Get(); err != nil {
return &Result{singular: isSingular, err: err}
}
visitors = append(visitors, info)
}
return &Result{singular: isSingular, visitor: VisitorList(visitors), sources: visitors}
}
// visit items specified by paths