-
Notifications
You must be signed in to change notification settings - Fork 40.1k
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
add kubectl wait #64034
add kubectl wait #64034
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
This file is autogenerated, but we've stopped checking such files into the | ||
repository to reduce the need for rebases. Please run hack/generate-docs.sh to | ||
populate this file. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
This file is autogenerated, but we've stopped checking such files into the | ||
repository to reduce the need for rebases. Please run hack/generate-docs.sh to | ||
populate this file. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
This file is autogenerated, but we've stopped checking such files into the | ||
repository to reduce the need for rebases. Please run hack/generate-docs.sh to | ||
populate this file. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2382,7 +2382,11 @@ run_namespace_tests() { | |
# Post-condition: namespace 'my-namespace' is created. | ||
kube::test::get_object_assert 'namespaces/my-namespace' "{{$id_field}}" 'my-namespace' | ||
# Clean up | ||
kubectl delete namespace my-namespace | ||
kubectl delete namespace my-namespace --wait=false | ||
# make sure that wait properly waits for finalization | ||
kubectl wait --for=delete ns/my-namespace | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a chance that the deletion (as a result of To make this test case more reliable, we could start There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It isn't super important, the unit tests on this command are quite thorough compared to others There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also I chose a namespace because they tend to delete very slowly because of finalizers |
||
output_message=$(! kubectl get ns/my-namespace 2>&1 "${kube_flags[@]}") | ||
kube::test::if_has_string "${output_message}" ' not found' | ||
|
||
###################### | ||
# Pods in Namespaces # | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -21,16 +21,20 @@ import ( | |||||||||||||||
"strings" | ||||||||||||||||
"time" | ||||||||||||||||
|
||||||||||||||||
"github.com/golang/glog" | ||||||||||||||||
"github.com/spf13/cobra" | ||||||||||||||||
|
||||||||||||||||
"k8s.io/apimachinery/pkg/api/errors" | ||||||||||||||||
"k8s.io/apimachinery/pkg/api/meta" | ||||||||||||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||||||||||||
"k8s.io/apimachinery/pkg/util/wait" | ||||||||||||||||
"k8s.io/client-go/dynamic" | ||||||||||||||||
"k8s.io/kubernetes/pkg/kubectl" | ||||||||||||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" | ||||||||||||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | ||||||||||||||||
kubectlwait "k8s.io/kubernetes/pkg/kubectl/cmd/wait" | ||||||||||||||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions" | ||||||||||||||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers" | ||||||||||||||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" | ||||||||||||||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n" | ||||||||||||||||
) | ||||||||||||||||
|
@@ -106,8 +110,9 @@ type DeleteOptions struct { | |||||||||||||||
|
||||||||||||||||
Output string | ||||||||||||||||
|
||||||||||||||||
Mapper meta.RESTMapper | ||||||||||||||||
Result *resource.Result | ||||||||||||||||
DynamicClient dynamic.Interface | ||||||||||||||||
Mapper meta.RESTMapper | ||||||||||||||||
Result *resource.Result | ||||||||||||||||
|
||||||||||||||||
genericclioptions.IOStreams | ||||||||||||||||
} | ||||||||||||||||
|
@@ -122,7 +127,7 @@ func NewCmdDelete(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra | |||||||||||||||
Long: delete_long, | ||||||||||||||||
Example: delete_example, | ||||||||||||||||
Run: func(cmd *cobra.Command, args []string) { | ||||||||||||||||
o := deleteFlags.ToOptions(streams) | ||||||||||||||||
o := deleteFlags.ToOptions(nil, streams) | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you just pass There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another option is to pass There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Completing command's options in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @soltysh yes, but for some reason we don't invoke |
||||||||||||||||
if err := o.Complete(f, args, cmd); err != nil { | ||||||||||||||||
cmdutil.CheckErr(err) | ||||||||||||||||
} | ||||||||||||||||
|
@@ -138,6 +143,8 @@ func NewCmdDelete(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra | |||||||||||||||
|
||||||||||||||||
deleteFlags.AddFlags(cmd) | ||||||||||||||||
|
||||||||||||||||
cmd.Flags().Bool("wait", true, `If true, wait for resources to be gone before returning. This waits for finalizers.`) | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not include this flag into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shall we also say in the description that this flag is on by default? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Help lists defaults already. Delete is a wasteland of weird delegation. I don't think this needs plumbing that far. |
||||||||||||||||
|
||||||||||||||||
cmdutil.AddIncludeUninitializedFlag(cmd) | ||||||||||||||||
return cmd | ||||||||||||||||
} | ||||||||||||||||
|
@@ -167,6 +174,9 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, args []string, cmd *cobra.Co | |||||||||||||||
o.WaitForDeletion = true | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I noted in the other comment, this line becomes obsolete: |
||||||||||||||||
o.GracePeriod = 1 | ||||||||||||||||
} | ||||||||||||||||
if b, err := cmd.Flags().GetBool("wait"); err == nil { | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I understand correctly, there is no real case when There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It happens during bad delegation and this command is ripe with it |
||||||||||||||||
o.WaitForDeletion = b | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this seems to be the reason for defining the "wait" flag differently from the rest - reusing the existing kubernetes/pkg/kubectl/cmd/delete.go Line 259 in 0db40da
ReapResult for resources with reapers only. It's not used for resources that don't have reapers.Given the upcoming change to get rid of reapers completely in #63979, I would suggest not to bother with merging existing and new flags. Instead, I would just rename the existing flag to get rid of it completely later as part of #63979, as I did in https://github.com/kubernetes/kubernetes/pull/63695/files#diff-7c126b9106a83157d89a336103eb3dbbR108 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, once we add an explicit I mean the condition kubernetes/pkg/kubectl/cmd/delete.go Lines 163 to 168 in 0db40da
With the changes in this PR, WaitForDeletion is already true by default, i.e. it's consistent with the backward compatibility for grace period. And if the user explicitly sets --wait=false , we shouldn't override it there, I think?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To be clear about the change I propose: Get rid of the existing logic with conditions for setting internal There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Once reapers die, perhaps. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that's the goal of getting rid of reapers. The old logic will die. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think it falls out in the other direction. Reapers die and we remove this old codepath. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Once the reapers are dead, we can move the wait flag to |
||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
o.Reaper = f.Reaper | ||||||||||||||||
|
||||||||||||||||
|
@@ -194,6 +204,11 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, args []string, cmd *cobra.Co | |||||||||||||||
return err | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
o.DynamicClient, err = f.DynamicClient() | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest that we remove this code and always require DynamicClient to be non-nil in |
||||||||||||||||
if err != nil { | ||||||||||||||||
return err | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
return nil | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
|
@@ -300,8 +315,38 @@ func (o *DeleteOptions) DeleteResult(r *resource.Result) error { | |||||||||||||||
} | ||||||||||||||||
if found == 0 { | ||||||||||||||||
fmt.Fprintf(o.Out, "No resources found\n") | ||||||||||||||||
return nil | ||||||||||||||||
} | ||||||||||||||||
return nil | ||||||||||||||||
if !o.WaitForDeletion { | ||||||||||||||||
return nil | ||||||||||||||||
} | ||||||||||||||||
// if we don't have a dynamic client, we don't want to wait. Eventually when delete is cleaned up, this will likely | ||||||||||||||||
// drop out. | ||||||||||||||||
if o.DynamicClient == nil { | ||||||||||||||||
return nil | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
effectiveTimeout := o.Timeout | ||||||||||||||||
if effectiveTimeout == 0 { | ||||||||||||||||
// if we requested to wait forever, set it to a week. | ||||||||||||||||
effectiveTimeout = 168 * time.Hour | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure a week is needed 😉 I'd go with previous 5min being sufficient. |
||||||||||||||||
} | ||||||||||||||||
waitOptions := kubectlwait.WaitOptions{ | ||||||||||||||||
ResourceFinder: kubectlwait.ResourceFinderForResult(o.Result), | ||||||||||||||||
DynamicClient: o.DynamicClient, | ||||||||||||||||
Timeout: effectiveTimeout, | ||||||||||||||||
|
||||||||||||||||
Printer: printers.NewDiscardingPrinter(), | ||||||||||||||||
ConditionFn: kubectlwait.IsDeleted, | ||||||||||||||||
IOStreams: o.IOStreams, | ||||||||||||||||
} | ||||||||||||||||
err = waitOptions.RunWait() | ||||||||||||||||
if errors.IsForbidden(err) { | ||||||||||||||||
// if we're forbidden from waiting, we shouldn't fail. | ||||||||||||||||
glog.V(1).Info(err) | ||||||||||||||||
return nil | ||||||||||||||||
} | ||||||||||||||||
return err | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (o *DeleteOptions) cascadingDeleteResource(info *resource.Info) error { | ||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,7 @@ import ( | |
|
||
"github.com/spf13/cobra" | ||
|
||
"k8s.io/client-go/dynamic" | ||
"k8s.io/kubernetes/pkg/kubectl" | ||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions" | ||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" | ||
|
@@ -72,9 +73,10 @@ type DeleteFlags struct { | |
Output *string | ||
} | ||
|
||
func (f *DeleteFlags) ToOptions(streams genericclioptions.IOStreams) *DeleteOptions { | ||
func (f *DeleteFlags) ToOptions(dynamicClient dynamic.Interface, streams genericclioptions.IOStreams) *DeleteOptions { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So passing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but we're doing this so that other places in the code re-use and not create their own versions of wait. |
||
options := &DeleteOptions{ | ||
IOStreams: streams, | ||
DynamicClient: dynamicClient, | ||
IOStreams: streams, | ||
} | ||
|
||
// add filename options | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the golang "standard" of everything being New or Interface or Flags sucks. Search for anything like that in our codebase and you're screwed. golint is trying to enforce that on this package, so I'm blacklisting it all.
Also, who thought that was ever a good idea???