mirror of https://github.com/k3s-io/k3s
Add support for waiting by label selector or on all resources
Add test for multiple deletions in kubectl watchpull/564/head
parent
0c2613c71a
commit
4c31e9855d
|
@ -90,6 +90,8 @@ func NewWaitFlags(restClientGetter genericclioptions.RESTClientGetter, streams g
|
||||||
PrintFlags: genericclioptions.NewPrintFlags("condition met"),
|
PrintFlags: genericclioptions.NewPrintFlags("condition met"),
|
||||||
ResourceBuilderFlags: genericclioptions.NewResourceBuilderFlags().
|
ResourceBuilderFlags: genericclioptions.NewResourceBuilderFlags().
|
||||||
WithLabelSelector("").
|
WithLabelSelector("").
|
||||||
|
WithFieldSelector("").
|
||||||
|
WithAll(false).
|
||||||
WithAllNamespaces(false).
|
WithAllNamespaces(false).
|
||||||
WithAll(false).
|
WithAll(false).
|
||||||
WithLatest(),
|
WithLatest(),
|
||||||
|
@ -105,11 +107,12 @@ func NewCmdWait(restClientGetter genericclioptions.RESTClientGetter, streams gen
|
||||||
flags := NewWaitFlags(restClientGetter, streams)
|
flags := NewWaitFlags(restClientGetter, streams)
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "wait resource.group/name [--for=delete|--for condition=available]",
|
Use: "wait ([-f FILENAME] | resource.group/resource.name | resource.group [(-l label | --all)]) [--for=delete|--for condition=available]",
|
||||||
|
Short: "Experimental: Wait for a specific condition on one or many resources.",
|
||||||
|
Long: waitLong,
|
||||||
|
Example: waitExample,
|
||||||
|
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Short: "Experimental: Wait for a specific condition on one or many resources.",
|
|
||||||
Long: waitLong,
|
|
||||||
Example: waitExample,
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
o, err := flags.ToOptions(args)
|
o, err := flags.ToOptions(args)
|
||||||
cmdutil.CheckErr(err)
|
cmdutil.CheckErr(err)
|
||||||
|
|
|
@ -310,6 +310,58 @@ func TestWaitForDeletion(t *testing.T) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "handles watch delete multiple",
|
||||||
|
infos: []*resource.Info{
|
||||||
|
{
|
||||||
|
Mapping: &meta.RESTMapping{
|
||||||
|
Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource-1"},
|
||||||
|
},
|
||||||
|
Name: "name-foo-1",
|
||||||
|
Namespace: "ns-foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Mapping: &meta.RESTMapping{
|
||||||
|
Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource-2"},
|
||||||
|
},
|
||||||
|
Name: "name-foo-2",
|
||||||
|
Namespace: "ns-foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
|
||||||
|
fakeClient := dynamicfakeclient.NewSimpleDynamicClient(scheme)
|
||||||
|
fakeClient.PrependReactor("get", "theresource-1", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||||
|
return true, newUnstructured("group/version", "TheKind", "ns-foo", "name-foo-1"), nil
|
||||||
|
})
|
||||||
|
fakeClient.PrependReactor("get", "theresource-2", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||||
|
return true, newUnstructured("group/version", "TheKind", "ns-foo", "name-foo-2"), nil
|
||||||
|
})
|
||||||
|
fakeClient.PrependWatchReactor("theresource-1", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) {
|
||||||
|
fakeWatch := watch.NewRaceFreeFake()
|
||||||
|
fakeWatch.Action(watch.Deleted, newUnstructured("group/version", "TheKind", "ns-foo", "name-foo-1"))
|
||||||
|
return true, fakeWatch, nil
|
||||||
|
})
|
||||||
|
fakeClient.PrependWatchReactor("theresource-2", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) {
|
||||||
|
fakeWatch := watch.NewRaceFreeFake()
|
||||||
|
fakeWatch.Action(watch.Deleted, newUnstructured("group/version", "TheKind", "ns-foo", "name-foo-2"))
|
||||||
|
return true, fakeWatch, nil
|
||||||
|
})
|
||||||
|
return fakeClient
|
||||||
|
},
|
||||||
|
timeout: 10 * time.Second,
|
||||||
|
|
||||||
|
validateActions: func(t *testing.T, actions []clienttesting.Action) {
|
||||||
|
if len(actions) != 2 {
|
||||||
|
t.Fatal(spew.Sdump(actions))
|
||||||
|
}
|
||||||
|
if !actions[0].Matches("list", "theresource-1") {
|
||||||
|
t.Error(spew.Sdump(actions))
|
||||||
|
}
|
||||||
|
if !actions[1].Matches("list", "theresource-2") {
|
||||||
|
t.Error(spew.Sdump(actions))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "ignores watch error",
|
name: "ignores watch error",
|
||||||
infos: []*resource.Info{
|
infos: []*resource.Info{
|
||||||
|
|
|
@ -51,6 +51,7 @@ source "${KUBE_ROOT}/test/cmd/save-config.sh"
|
||||||
source "${KUBE_ROOT}/test/cmd/storage.sh"
|
source "${KUBE_ROOT}/test/cmd/storage.sh"
|
||||||
source "${KUBE_ROOT}/test/cmd/template-output.sh"
|
source "${KUBE_ROOT}/test/cmd/template-output.sh"
|
||||||
source "${KUBE_ROOT}/test/cmd/version.sh"
|
source "${KUBE_ROOT}/test/cmd/version.sh"
|
||||||
|
source "${KUBE_ROOT}/test/cmd/wait.sh"
|
||||||
|
|
||||||
|
|
||||||
ETCD_HOST=${ETCD_HOST:-127.0.0.1}
|
ETCD_HOST=${ETCD_HOST:-127.0.0.1}
|
||||||
|
@ -832,6 +833,12 @@ runTests() {
|
||||||
#################
|
#################
|
||||||
record_command run_impersonation_tests
|
record_command run_impersonation_tests
|
||||||
|
|
||||||
|
####################
|
||||||
|
# kubectl wait #
|
||||||
|
####################
|
||||||
|
|
||||||
|
record_command run_wait_tests
|
||||||
|
|
||||||
kube::test::clear_all
|
kube::test::clear_all
|
||||||
|
|
||||||
if [[ -n "${foundError}" ]]; then
|
if [[ -n "${foundError}" ]]; then
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright 2018 The Kubernetes Authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o nounset
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
run_wait_tests() {
|
||||||
|
set -o nounset
|
||||||
|
set -o errexit
|
||||||
|
|
||||||
|
kube::log::status "Testing kubectl wait"
|
||||||
|
|
||||||
|
create_and_use_new_namespace
|
||||||
|
|
||||||
|
### Wait for deletion using --all flag
|
||||||
|
|
||||||
|
# create test data
|
||||||
|
kubectl create deployment test-1 --image=busybox
|
||||||
|
kubectl create deployment test-2 --image=busybox
|
||||||
|
|
||||||
|
# Post-Condition: deployments exists
|
||||||
|
kube::test::get_object_assert "deployments" "{{range .items}}{{.metadata.name}},{{end}}" 'test-1,test-2,'
|
||||||
|
|
||||||
|
# Delete all deployments async to kubectl wait
|
||||||
|
( sleep 2 && kubectl delete deployment --all ) &
|
||||||
|
|
||||||
|
# Command: Wait for all deployments to be deleted
|
||||||
|
output_message=$(kubectl wait deployment --for=delete --all)
|
||||||
|
|
||||||
|
# Post-Condition: Wait was successful
|
||||||
|
kube::test::if_has_string "${output_message}" 'test-1 condition met'
|
||||||
|
kube::test::if_has_string "${output_message}" 'test-2 condition met'
|
||||||
|
|
||||||
|
set +o nounset
|
||||||
|
set +o errexit
|
||||||
|
}
|
Loading…
Reference in New Issue