Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support for multiple resources to kubectl #4667

Merged
merged 1 commit into from
Feb 23, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 21 additions & 0 deletions hack/test-cmd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,15 @@ for version in "${kube_api_versions[@]}"; do
kubectl get pods "${kube_flags[@]}" -lname=redis-master | grep -q 'redis-master'
[ ! $(delete pods --all pods -l name=redis-master) ] # not --all and label selector together
kubectl delete --all pods "${kube_flags[@]}" # --all remove all the pods
kubectl create -f examples/guestbook/redis-master.json "${kube_flags[@]}"
kubectl create -f examples/redis/redis-proxy.yaml "${kube_flags[@]}"
kubectl get pods redis-master redis-proxy "${kube_flags[@]}"
kubectl delete pods redis-master redis-proxy # delete multiple pods at once
howmanypods="$(kubectl get pods -o template -t "{{ len .items }}" "${kube_flags[@]}")"
[ "$howmanypods" -eq 0 ]
kubectl create -f examples/guestbook/redis-master.json "${kube_flags[@]}"
kubectl create -f examples/redis/redis-proxy.yaml "${kube_flags[@]}"
kubectl stop pods redis-master redis-proxy # stop multiple pods at once
howmanypods="$(kubectl get pods -o template -t "{{ len .items }}" "${kube_flags[@]}")"
[ "$howmanypods" -eq 0 ]

Expand Down Expand Up @@ -185,13 +194,25 @@ __EOF__
kubectl get services "${kube_flags[@]}"
kubectl get services "service-${version}-test" "${kube_flags[@]}"
kubectl delete service frontend "${kube_flags[@]}"
servicesbefore="$(kubectl get services -o template -t "{{ len .items }}" "${kube_flags[@]}")"
kubectl create -f examples/guestbook/frontend-service.json "${kube_flags[@]}"
kubectl create -f examples/guestbook/redis-slave-service.json "${kube_flags[@]}"
kubectl delete services frontend redisslave # delete multiple services at once
servicesafter="$(kubectl get services -o template -t "{{ len .items }}" "${kube_flags[@]}")"
[ "$((${servicesafter} - ${servicesbefore}))" -eq 0 ]

kube::log::status "Testing kubectl(${version}:replicationcontrollers)"
kubectl get replicationcontrollers "${kube_flags[@]}"
kubectl create -f examples/guestbook/frontend-controller.json "${kube_flags[@]}"
kubectl get replicationcontrollers "${kube_flags[@]}"
kubectl describe replicationcontroller frontend-controller "${kube_flags[@]}" | grep -q 'Replicas:.*3 desired'
kubectl delete rc frontend-controller "${kube_flags[@]}"
rcsbefore="$(kubectl get replicationcontrollers -o template -t "{{ len .items }}" "${kube_flags[@]}")"
kubectl create -f examples/guestbook/frontend-controller.json "${kube_flags[@]}"
kubectl create -f examples/guestbook/redis-slave-controller.json "${kube_flags[@]}"
kubectl delete rc frontend-controller redis-slave-controller "${kube_flags[@]}" # delete multiple controllers at once
rcsafter="$(kubectl get replicationcontrollers -o template -t "{{ len .items }}" "${kube_flags[@]}")"
[ "$((${rcsafter} - ${rcsbefore}))" -eq 0 ]

kube::log::status "Testing kubectl(${version}:nodes)"
kubectl get nodes "${kube_flags[@]}"
Expand Down
72 changes: 43 additions & 29 deletions pkg/kubectl/resource/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ type Builder struct {
resources []string

namespace string
name string
names []string

defaultNamespace bool
requireNamespace bool
Expand Down Expand Up @@ -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 len(args) == 2:
b.names = append(b.names, args[1])
b.ResourceTypes(SplitResourceArgument(args[0])...)
case 1:
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"))
}
Expand All @@ -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:
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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]

client, err := b.mapper.ClientForMapping(mapping)
if err != nil {
return &Result{err: err}
}

selectorNamespace := b.namespace
if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
b.namespace = ""
selectorNamespace = ""
} else {
if len(b.namespace) == 0 {
return &Result{singular: true, err: fmt.Errorf("namespace may not be empty when retrieving a resource by name")}
return &Result{singular: isSingular, 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}
}
info := NewInfo(client, mappings[0], b.namespace, b.name)
if err := info.Get(); err != nil {
return &Result{singular: true, err: err}

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: true, visitor: info, sources: []Visitor{info}}
return &Result{singular: isSingular, visitor: VisitorList(visitors), sources: visitors}
}

// visit items specified by paths
Expand Down