mirror of https://github.com/k3s-io/k3s
Adds support for multiple resources to kubectl
You can specify multiple resources by name when using the delete, get and stop commands.pull/6/head
parent
0e1c0b26dc
commit
ecbb91cc08
|
@ -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 ]
|
||||
|
||||
|
@ -185,6 +194,12 @@ __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[@]}"
|
||||
|
@ -192,6 +207,12 @@ __EOF__
|
|||
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[@]}"
|
||||
|
|
|
@ -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)
|
||||
|
||||
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")}
|
||||
}
|
||||
}
|
||||
|
||||
visitors := []Visitor{}
|
||||
for _, name := range b.names {
|
||||
info := NewInfo(client, mapping, selectorNamespace, name)
|
||||
if err := info.Get(); err != nil {
|
||||
return &Result{singular: true, err: err}
|
||||
return &Result{singular: isSingular, err: err}
|
||||
}
|
||||
return &Result{singular: true, visitor: info, sources: []Visitor{info}}
|
||||
visitors = append(visitors, info)
|
||||
}
|
||||
return &Result{singular: isSingular, visitor: VisitorList(visitors), sources: visitors}
|
||||
}
|
||||
|
||||
// visit items specified by paths
|
||||
|
|
Loading…
Reference in New Issue